• uva12534 Binary Matrix 2(最小费用最大流)


    http://blog.csdn.net/qq564690377/article/details/17082055

    做的时候觉得明显是费用流,但是真的不知道怎么建图,看了上面的博客会稍微清晰一点。后面再补一点细节吧,然后发现这道题用自己平时的费用流模板是水不过去的,所以找了份别人AC的代码弄了个zkw最小费用流的模板上来,算是存下模板吧。

    补充点个人的理解吧,个人的网络流做的题还是太少了,所以想不到怎么建模,其实感觉上还是比较直接的一个行列二分图建模。首先就是枚举最后有多少个1剩下来,假设当前的已经有cur个1了,然后我要达到tot,那么每一行应该有tot/n个,每一列应该有tot/m个,所以我们可以对每行建一个点,对每列建一个点,从源点到行的点限流tot/n,列的点到汇点限流tot/m,这样的话当满流的时候其实就能保证每一行的1相等,每一列的1也相等。然后建边的时候就是每个处于(i,j)的点和i行j列的点连一条边,假设原本是1就费用为0,原本是0就费用为1.那么按照这样跑一遍费用流,费用x就是图里面需要由0变成1的点的个数,我们只需要再求出y,即图里由1变成0的个数就可以了。那么y等于多少呢? 不难发现图中多出来的1应该满足 x-y=tot-cur  所以y=x+cur-tot  所以最后的费用是x+y=2*x+cur-tot。

    http://blog.sina.com.cn/s/blog_61034ad90100gwdw.html

    上面的博客研究了spfa的网络流和zkw的网络流,可能zkw网络流会比较适用在二分图,稠密图上吧。

    #pragma warning(disable:4996)
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <cmath>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    using namespace std;
    
    #define ll long long
    #define eps 1e-8
    #define maxn 100
    #define maxe 4000
    #define inf 0x3f3f3f3f
    using namespace std;
    
    
    char b[50][50];
    int n, m;
    
    /*int siz;
    
    struct Edge{
    int u, v, nxt, cap, cost;
    }edge[maxe];
    int head[maxn];
    
    
    struct MinCostMaxFlow
    {
    	queue<int> que;
    	int add; // edges number
    	int vn; // total vertex number
    	int cost[maxn], in[maxn], pre[maxn];
    	bool vis[maxn];
    	void init(){
    		add = 0; vn = siz + 10; memset(head, -1, sizeof(head));
    		while (!que.empty()) que.pop();
    	}
    	void insert(int u, int v, int w, int c){
    		edge[add].u = u; edge[add].v = v; edge[add].cap = w; edge[add].cost = c;
    		edge[add].nxt = head[u]; head[u] = add++;
    		edge[add].u = v; edge[add].v = u; edge[add].cap = 0; edge[add].cost = -c;
    		edge[add].nxt = head[v]; head[v] = add++;
    	}
    
    	bool spfa(int s, int e){
    		memset(cost, 0x3f3f3f3f, sizeof(cost));
    		memset(in, 0, sizeof(in));
    		memset(vis, 0, sizeof(vis));
    		cost[s] = 0; pre[s] = -1;
    		que.push(s); vis[s] = true; in[s]++;
    		while (!que.empty()){
    			int u = que.front(); que.pop();
    			vis[u] = false;
    			for (int i = head[u]; i != -1; i = edge[i].nxt){
    				int v = edge[i].v;
    				if (edge[i].cap > 0 && cost[v] > cost[u] + edge[i].cost){
    					cost[v] = cost[u] + edge[i].cost; pre[v] = i;
    					if (!vis[v]){
    						que.push(v); vis[v] = true; in[v]++;
    						if (in[v] > vn) return false;
    					}
    				}
    			}
    		}
    		if (cost[e] < inf) return true;
    		else return false;
    	}
    	int mincostmaxflow(int s, int e){
    		int mincost = 0, maxflow = 0;
    		while (spfa(s, e)){
    			int flow = inf;
    			for (int i = pre[e]; i != -1; i = pre[edge[i].u]){
    				flow = min(flow, edge[i].cap);
    			}
    			maxflow += flow;
    			for (int i = pre[e]; i != -1; i = pre[edge[i].u]){
    				edge[i].cap -= flow;
    				edge[i ^ 1].cap += flow;
    			}
    			mincost += cost[e] * flow;
    		}
    		return mincost;
    	}
    }net;
    */
    
    
    struct Edge
    {
    	int u, v, cap, cost, nxt;
    	Edge(int _u, int _v, int _cap, int _cost, int _nxt) :
    		u(_u), v(_v), cap(_cap), cost(_cost), nxt(_nxt){}
    	Edge(){};
    }edge[maxe];
    int head[maxn];
    
    struct ZKW_MinCostMaxFlow {
    	int add;
    	int cur[maxn];
    	int dis[maxn];
    	bool inq[maxn];
    	queue<int> q;
    	bool vis[maxn];
    
    	int ss, tt, n;
    	int min_cost, max_flow;
    
    	void init() {
    		memset(head, -1, sizeof(head));
    		add = 0;
    	}
    
    	void insert(int u, int v, int cp, int ct) {
    		edge[add] = Edge(u, v, cp, ct, head[u]);
    		head[u] = add++;
    		edge[add] = Edge(v, u, 0, -ct, head[v]);
    		head[v] = add++;
    	}
    
    	int aug(int u, int flow) {
    		if (u == tt) return flow;
    		vis[u] = true;
    		for (int i = cur[u]; i != -1; i = edge[i].nxt) {
    			int v = edge[i].v;
    			if (edge[i].cap && !vis[v] && dis[u] == dis[v] + edge[i].cost) {
    				int tmp = aug(v, min(flow, edge[i].cap));
    				edge[i].cap -= tmp;
    				edge[i ^ 1].cap += tmp;
    				cur[u] = i;
    				if (tmp) return tmp;
    			}
    		}
    		return 0;
    	}
    	bool modify_label() {
    		int d = inf;
    		for (int u = 0; u < n; u++) if (vis[u])
    		for (int i = head[u]; i != -1; i = edge[i].nxt) {
    			int v = edge[i].v;
    			if (edge[i].cap && !vis[v])
    				d = min(d, dis[v] + edge[i].cost - dis[u]);
    		}
    		if (d == inf) return false;
    		for (int i = 0; i < n; ++i) if (vis[i]) {
    			vis[i] = false;
    			dis[i] += d;
    		}
    		return true;
    	}
    
    	pair<int, int> mincostmaxflow(int s, int t, int _n) {
    		ss = s, tt = t, n = _n;
    		min_cost = max_flow = 0;
    		for (int i = 0; i < n; i++) dis[i] = 0;
    		while (true) {
    			for (int i = 0; i < n; i++) cur[i] = head[i];
    			while (true) {
    				for (int i = 0; i < n; i++) vis[i] = 0;
    				int tmp = aug(s, inf);
    				if (tmp == 0) break;
    				max_flow += tmp;
    				min_cost += tmp * dis[ss];
    			}
    			if (!modify_label()) break;
    		}
    		return make_pair(min_cost, max_flow);
    	}
    }net;
    
    int main()
    {
    	int T; cin >> T; int ca = 0;
    	while (T--){
    		scanf("%d%d", &n, &m);
    		for (int i = 0; i < n; i++) scanf("%s", b[i]);
    		int tot = 0;
    		for (int i = 0; i < n; ++i){
    			for (int j = 0; j < m; ++j){
    				if (b[i][j] == '1') tot++;
    			}
    		}
    		int ans = min(n*m - tot, tot);
    		for (int i = 1; i <= n*m; ++i){
    			if (i%n != 0 || i%m != 0) continue;
    			if (abs(tot - i) >= ans) continue;
    			net.init();
    			int src = n + m, sink = src + 1;
    			for (int k = 0; k < n; ++k){
    				net.insert(src, k, i / n, 0);
    			}
    			for (int k = n; k < n + m; k++){
    				net.insert(k, sink, i / m, 0);
    			}
    			for (int x = 0; x < n; x++){
    				for (int j = 0; j < m; j++){
    					if (b[x][j] == '1') net.insert(x, j + n, 1, 0);
    					else net.insert(x, j + n, 1, 1);
    				}
    			}
    			ans = min(ans, net.mincostmaxflow(src, sink,sink+1).first * 2 + tot - i);
    		}
    		printf("Case %d: %d
    ", ++ca, ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    第三套三
    多线程读写共享变量时,synchronized与volatile的作用
    jQuery源代码学习笔记:构造jQuery对象
    写入位置时发生訪问冲突
    Free Editor
    大区间素数筛选 POJ2689
    HDU
    CentOS下挂载U盘
    得到当前堆栈信息的两种方式(Thread和Throwable)的纠结
    [实战]MVC5+EF6+MySql企业网盘实战(9)——编辑文件名
  • 原文地址:https://www.cnblogs.com/chanme/p/3872266.html
Copyright © 2020-2023  润新知