POJ 2195 Going Home

题目链接:Going Home

解题思路:最小费用最大流的问题,建图的时候要有超级源点和超级汇点,源点连接所有的小孩,花费为0,容量为1,所有的房子连接超级汇点,花费和容量与上边相同。然后每个孩子和每个房子连接一条路径,花费为两点距离   abs(x1 - x2)+ abs(y1 - y2),容量为1。在原图的基础上面建立花费图,如果两点的正向边的容量不为0的话那么就为w,反向变不为0的话就为-w。

算法的核心思想就是通过寻找花费图源点到汇点的最短路径。这个路径就是增广1单位容量花费的钱数。如果最后不存在最短路径的话说明汇点已经达到最大流。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<stdlib.h>
#include<vector>
#define MAXN 5000
#define MAXM 50000
#define INF 0x3f3f3f3f

using namespace std;

typedef struct A{
	int x, y;
	A(){}
	A(int a, int b){
		x = a, y = b;
	}
}node;

typedef struct B{
	int e, c, v, nxt;
	B(){}
	B(int a, int b, int q, int d){
		e = a, c = b, v = q, nxt = d;
	}
}edge;

bool vis[MAXN];
edge Map[MAXM];
int g[MAXN];
int dis[MAXN];
int pree[MAXN], prev[MAXN];
vector<node> mm, hh;
int tot = 2, n, m;

int minNum(int a, int b){
	return a < b ? a : b;
}

void addedge(int u, int v, int c, int w){
	Map[tot] = edge(v, c, w, g[u]);
	g[u] = tot++;
	Map[tot] = edge(u, 0, -1 * w, g[v]);
	g[v] = tot++;
}

void init(){
	mm.clear();
	hh.clear();
	tot = 2;
	memset(g, 0, sizeof(g));
	memset(Map, 0, sizeof(Map));
	memset(pree, 0, sizeof(pree));
	memset(prev, 0, sizeof(prev));
}

bool spfa(){
	int i, j, sink = mm.size() * 2 + 1;
	queue<int> que;
	memset(vis, false, sizeof(vis));
	memset(dis, 127, sizeof(dis));
	que.push(0);
	dis[0] = 0;
	vis[0] = true;
	while(!que.empty()){
		int s = que.front();
		que.pop();
		for(i = g[s]; i; i = Map[i].nxt){
			if(Map[i].c && dis[Map[i].e] > dis[s] + Map[i].v){
				dis[Map[i].e]  = dis[s] + Map[i].v;
				pree[Map[i].e] = i;
				prev[Map[i].e] = s;
				if(!vis[Map[i].e]){
					que.push(Map[i].e);
					vis[Map[i].e] = true;
				}
			}
		}
		vis[s] = false;
	}
	if(dis[sink] < INF){
		return true;
	}
	return false;
}

int slove(){
	int u = mm.size() * 2 + 1;
	int detla = INF;
	while(u != 0){
		if(Map[pree[u]].c < detla){
			detla  = Map[pree[u]].c;
		}
		u = prev[u];
	}
	u = mm.size() * 2 + 1;
	while(u != 0){
		Map[pree[u]].c -= detla;
		Map[pree[u] ^ 1].c += detla;
		u = prev[u];
	}
	return dis[mm.size() * 2 + 1] * detla;
}

int mincostflow(){
	int ret = 0;
	while(spfa()){
		ret += slove();
	}
	return ret;
}

int main(){
	int i, j, k;
	char p;
//	freopen("in.txt", "r", stdin);
	while(scanf("%d%d", &n, &m) && (n || m)){
		init();
		for(i = 0; i < n; i++){
			getchar();
			for(j = 0; j < m; j++){
				scanf("%c", &p);
				if(p == 'H'){
					hh.push_back(node(i, j));
				}
				if(p == 'm'){
					mm.push_back(node(i, j));
				}
			}
		}/*
		for(i = 0; i < hh.size(); i++){
			printf("%d %d ------%d %d\n", hh[i].x, hh[i].y, mm[i].x, mm[i].y);
		}*/
		for(i = 0; i < mm.size(); i++){
			addedge(0, i + 1, 1, 0);
			addedge(i + 1 + mm.size(), mm.size() *  2 + 1, 1, 0);
			for(j = 0; j < hh.size(); j++){
				addedge(i + 1, j + 1 + hh.size(), 1, abs(mm[i].x - hh[j].x) + abs(mm[i].y - hh[j].y));
			}
		}
		printf("%d\n", mincostflow());
	}
	return 0;
}


 

你可能感兴趣的:(POJ 2195 Going Home)