[2014BOP预选赛_C]格格取数
来源:互联网 发布:网络电视台解决方案 编辑:程序博客网 时间:2024/04/28 15:48
解题思路:
觉得是最小费用流,但是当时不知道怎么建图。
首先很容易想到这样的做法:源s向行i连一条流量为1,费用为0的边,列j同样向汇t连一条流量为1,费用为0的边,然后ij间连一条流量为1,费用为a[i][j]的边。如果n==m,显然这样做保证了每行每列都被取到了。
但是当n!=m的时候,总有一些行和列没有匹配到。
就算是n==m的时候,我们只是保证了每行每列都被取到,但是这却不一定是最优解。
比如:
0 0 0
1 1 0
1 1 0
归根结底是我们限制了每行每列最多只能取一次。
解决方法的方法是加入补充边集。
过于抽象我也不知道怎么说。
参考:http://blog.csdn.net/cqsh3vj2/article/details/23624495?reload
首先约束覆盖,保证每行每列都取到了。
然后提供边,让每行每列允许取多次。
至于s-t中连一条容量为m*n,费用为0的边的原因是:这个图显然最大流是m*n,若不加这条边那么就等于整个矩阵的数取了个遍(先满足最大流再满足最小费用),也就是这条边是用来分流的。
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <map>#include <set>#include <vector>#include <utility>#include <queue>#include <stack>#include <cstdlib>#include <ctime>using namespace std;#pragma comment(linker,"/STACK:102400000,102400000")#define LL long long#define ULL unsigned long long#define Hei cout << "Czy!!!" << endl;#define lson rt << 1, l, mid#define rson rt << 1 | 1, mid + 1, r#define MOD 1000000007#define INF 10000#define maxn 100/* clock_t t1, t2; t1 = clock(); t2 = clock(); cout << (double)(t2 - t1) / CLOCKS_PER_SEC << endl;*/int a[maxn][maxn];struct Edge{ int from, to, cap, flow, cost; Edge(int from = 0, int to = 0, int cap = 0, int flow = 0, int cost = 0): from(from), to(to), cap(cap), flow(flow), cost(cost) {}};vector<Edge> edges;vector<int> G[maxn];void AddEdge(int from, int to, int cap, int cost){ edges.push_back(Edge(from, to, cap, 0, cost)); edges.push_back(Edge(to, from, 0, 0, -cost)); int m = edges.size(); G[from].push_back(m - 2); G[to].push_back(m - 1);}struct MCMF{ int n, s, t; int inq[maxn]; int d[maxn]; int p[maxn]; int a[maxn]; void init(int n) { this->n = n; for (int i = 0; i <= n; i++) G[i].clear(); edges.clear(); } bool Spfa(int s, int t, int &flow, int &cost) { for (int i = 0; i <= n; i++) d[i] = INF; memset(inq, 0, sizeof(inq)); d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF; queue<int> Q; Q.push(s); while (!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = 0; for (int i = 0; i < G[u].size(); i++) { Edge &e = edges[G[u][i]]; if (e.cap > e.flow && d[e.to] > d[u] + e.cost) { d[e.to] = d[u] + e.cost; p[e.to] = G[u][i]; a[e.to] = min(a[u], e.cap - e.flow); if (!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; } } } } if (d[t] == INF) return false; flow += a[t]; cost += d[t] * a[t]; int u = t; while (u != s) { edges[p[u]].flow += a[t]; edges[p[u] ^ 1].flow -= a[t]; u = edges[p[u]].from; } return true; } int Mincost(int s, int t) { int flow = 0, cost = 0; while (Spfa(s, t, flow, cost)); return cost; }}solver;int main(){ int T; cin >> T; while (T--) { int n, m; cin >> n >> m; solver.init(2 * n + 2 * m + 3); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", &a[i][j]); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { AddEdge(i, 2 * n + j, 1, a[i][j]); AddEdge(i, 2 * n + m + j, 1, a[i][j]); AddEdge(n + i, 2 * n + j, 1, a[i][j]); AddEdge(n + i, 2 * n + m + j, 1, a[i][j]); } for (int i = 1; i <= n; i++) { AddEdge(0, i, 1, -INF); AddEdge(0, i + n, m, 0); } for (int i = 1; i <= m; i++) { AddEdge(2 * n + i, 2 * n + 2 * m + 1, 1, -INF); AddEdge(2 * n + m + i, 2 * n + 2 * m + 1, m, 0); } AddEdge(0, 2 * n + 2 * m + 1, m * n, 0); AddEdge(2 * n + 2 * m + 2, 0, m * n, 0); AddEdge(2 * n + 2 * m + 1, 2 * n + 2 *m + 3, m * n, 0); //for (int i = 1; i <= m; i++) AddEdge(i + n, 2 * n + m + 1, 1, -INF); int x = solver.Mincost(2 * n + 2 * m + 2, 2 * n + 2 * m + 3) ; cout << x + (n + m) * INF<< endl; }}
0 0
- [2014BOP预选赛_C]格格取数
- 编程之美2014格格取数
- 编程之美2014格格取数
- 编程之美2014格格取数
- 编程之美2014格格取数(回溯法)
- 2014编程之美资格赛 题目3 : 格格取数
- 编程之美2014资格赛题目3:格格取数
- 2014编程之美资格赛第三题-格格取数
- 编程之美 格格取数问题
- 编程之美之格格取数
- 编程之美-格格取数
- [2014]编程之美第3题,格格取数问题
- 2014 编程之美 资格赛 第三题 格格取数(二分图带权最小边覆盖)
- 编程之美 2014 格格取数(最小费用最大流)
- 2014 编程之美 预赛第三题 格格取数 上下界费用流
- 编程之美2014资格赛 hihoCoder 题目3:格格取数
- 编程之美2014年资格赛第三题格格取数
- 编程之美 打酱油 格格取数
- 距离空间,线性空间,赋范线性空间,Banach空间,内积空间,Hilbert空间的内在关系
- Linux下用Qt实现摄像
- nyoj61(双线背包)
- 第四章作业
- Android 样式和主题
- [2014BOP预选赛_C]格格取数
- JS:window.onload的使用
- Java安全之对称加密与非对称加密
- C#循环语句(while语句和for语句)
- 选择类排序-堆排序
- Android单元测试初探——Instrumentation
- 索引原理(1)
- Makefile 语法
- IOS App自定义URL scheme