poj2195 Going Home

一个n*m个grid上面有x个man和x个house,现在就是man每移动一步就需要花费1元,现在就是x个人要找房子呆着,且一个房子只能容纳一个人,求所有人找到呆着的房子的最小花费。

建立一个超级源点s和汇点t,s到每个人建立一条容量为1、费用为0的边,每个人到每个房子建立一条容量为inf、费用为两者间的最小距离,方向变的费用为负,房子到t建立一条容量为1、费用为0的边。。。

/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2015
File Name   :
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
#define MEM(x,y) memset(x, y,sizeof x)
#define pk push_back
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
typedef pair<ii,int> iii;
const double eps = 1e-10;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 110;
int cap[maxn*2][maxn*2], pre[maxn*2], cost[maxn*2][maxn*2];
vector<ii> men,house;
int s, t;
char str[maxn];
int n, m;
int num;
bool vis[maxn*2];
int dis[maxn*2];
bool spfa() {
	queue<int> que;
	memset(dis, INF,sizeof dis);
	memset(vis, false,sizeof vis);
	memset(pre, -1,sizeof pre);
	dis[s] = 0,vis[s] = true;
	que.push(s);
	while(!que.empty()) {
		int u = que.front();
		que.pop();
		vis[u] = false;
		for (int v = s;v <= t;++v) {
			if (cap[u][v] > 0 && dis[v] > dis[u] + cost[u][v]) {
				dis[v] = dis[u] + cost[u][v];
				pre[v] = u;
				if (!vis[v]) {
					vis[v] = true;
					que.push(v);
				}
			}
		}
	}
	return pre[t] != -1;
}
int MCMF() {
	int ret = 0;
	while(spfa()) {
		for (int v = t;v != s;v = pre[v]) {
			cap[pre[v]][v] -= 1;
			cap[v][pre[v]] += 1;
		}
		ret += dis[t];
	}
	return ret;
}
int main()
{	
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	while(scanf("%d%d",&n,&m)) {
		if (n==0&&m==0) break;
		men.clear(),house.clear();
		for (int i = 1;i <= n;++i) {
			scanf("%s",str+1);
			for (int j = 1;j <= m;++j) {
				if (str[j] == 'H') house.push_back(ii(i, j));
				if (str[j] == 'm') men.push_back(ii(i, j));
			}
		}
		memset(cap, 0,sizeof cap);
		memset(cost, 0,sizeof cost);
		num = (int)men.size();
		s = 0, t = num*2+1;
		for (int i = 0;i < num;++i) {
			int u = i + 1;
			cap[s][u] = 1;
			for (int j = 0;j < num;++j) {
				int dis = abs(men[i].first - house[j].first) + abs(men[i].second - house[j].second);
				int v = j + 1 + num;
				cap[v][t] = 1;
				cap[u][v] = INF;
				cost[u][v] = dis;
				cost[v][u] = -dis;
			}
		}
		printf("%d\n", MCMF());
	}
	return 0;
}

/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2016
File Name   :
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
#define MEM(x,y) memset(x, y,sizeof x)
#define pk push_back
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
typedef pair<ii,int> iii;
const double eps = 1e-10;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 110;
struct Point{
	int x,y;
	Point(){}
	Point(int x,int y):x(x),y(y){}
	int operator - (const Point& rhs) {
		return abs(x - rhs.x) + abs(y - rhs.y);
	}
}A[maxn],B[maxn];
int cnt1,cnt2;
int n, m;
char str[maxn];
int head[maxn*2],cap[maxn*maxn*2],flow[maxn*maxn*2],nxt[maxn*maxn*2],cost[maxn*maxn*2],pnt[maxn*maxn*2];
int pre[maxn*2];
int ecnt;
int s, t;
inline void addedge(int u,int v,int c,int w) {
	cap[ecnt] = c, flow[ecnt] = 0,cost[ecnt] = w,pnt[ecnt] = v;
	nxt[ecnt] = head[u],head[u] = ecnt++;
	
	cap[ecnt] = 0,flow[ecnt] = 0,cost[ecnt] = -w,pnt[ecnt] = u;
	nxt[ecnt] = head[v],head[v] = ecnt++;
}
int dis[maxn*2];
bool vis[maxn*2];
bool spfa() {
	queue<int> que;
	memset(pre, -1,sizeof pre);
	memset(dis, INF,sizeof dis);
	memset(vis, false,sizeof vis);
	que.push(s);
	vis[s] = true;
	dis[s] = 0;
	while(!que.empty()) {
		int u = que.front();
		que.pop();
		vis[u] = false;
		for (int i = head[u];i != -1;i = nxt[i]) {
			int v = pnt[i];
			if (cap[i] > flow[i] && dis[v] > dis[u] + cost[i]) {
				dis[v] = dis[u] + cost[i];
				pre[v] = i;
				if (!vis[v]) {
					vis[v] = true;
					que.push(v);
				}
			}
		}
	}
	return dis[t] != INF;
}
int MCMF() {
	int ret = 0;
	while(spfa()) {
		int minflow = INF;
		for (int v = t;v != s;v = pnt[pre[v]^1]) {
			int i = pre[v];
			minflow = min(minflow, cap[i] - flow[i]);
		}
		ret += minflow * dis[t];
		for (int v = t;v != s;v = pnt[pre[v]^1]) {
			int i = pre[v];
			flow[i] += minflow;
			flow[i^1] -= minflow;
			if (pre[v]==-1)break;
		}
	}
	return ret;
}
int main()
{	
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	while(scanf("%d%d",&n,&m)) {
		if (n==0&&m==0)break;
		cnt1 = cnt2 = 0;
		for (int i = 1;i <= n;++i) {
			scanf("%s",str+1);
			for (int j = 1;j <= m;++j) {
				if (str[j] == 'H') A[++cnt1] = Point(i, j);
				if (str[j] == 'm') B[++cnt2] = Point(i, j);
			}
		}
		s = 0,t = 2*cnt1+1;
		memset(head, -1,sizeof head);
		ecnt = 0;
		for (int i = 1;i <= cnt1;++i) {//cnt1 == cnt2;
			addedge(s, i, 1, 0);
			addedge(i+cnt1, t, 1, 0);
			for (int j = 1;j <= cnt2;++j) {
				int dis = A[i] - B[j];
				addedge(i,j+cnt1,INF,dis);
			}
		}
		printf("%d\n", MCMF());
	}
	return 0;
}


你可能感兴趣的:(poj,最小费用最大流)