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\n", ++ca, ans);
	}
	return 0;
}

 

posted @ 2014-07-28 00:27  chanme  阅读(185)  评论(0编辑  收藏  举报