POJ - 2195 (二分最小权匹配 && 最小费用最大流)

题目连接

题意:
                图上,N个小矮人,N个房子,每个单位时间内
                每个小矮人都能水平或者垂直移动一个单位步长到相邻的点。
                每次移动消费1块钱,直到他进入房屋,每个房子只能容纳一个小矮人
                
                问支付最低的金额。将这N个小矮人送入这N个不同的房间  
    数据范围:
                1 s
                N  M < 100 
                N * M的矩阵, H是房子。m是人 
    思路: 
                为每个小矮人找到房子,
                1)求最小权下的二分匹配 
                2)费用流:最小费用最大流
                    建图:源点 - 人 流量1, 费用0 
                            人-房子 流量1,费用曼哈顿距离
                            房子-汇点 流量1,费用0
                    跑个费用流

最小权二分匹配AC:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 205;
const int INF = 0x3f3f3f3f;
vector < pair > G[maxn * 2];
bool vis_X[maxn], vis_Y[maxn];
int ex_X[maxn], ex_Y[maxn];
int Match[maxn];
int Slack[maxn];

int CntPeo = 1, CntHome = 1;
struct node{
	int x, y;
}Peo[maxn],Home[maxn];

void init(){
	CntPeo = 1;
	CntHome = 1;
    
}
bool Dfs(int x){
    vis_X[x] = 1;
    int v, c;
    for (int i = 0; i < G[x].size(); ++i) {
        v = G[x][i].first;
        c = G[x][i].second;
        if (vis_Y[v]) continue;
        int Tmp = ex_X[x] + ex_Y[v] - c;
        if (Tmp != 0) {
            Slack[v] = min (Slack[v], Tmp);
        } else {
            vis_Y[v] = 1;
            if (Match[v] == -1 || Dfs(Match[v])) {
                Match[v] = x;
                //cout << v << " " << Match[v] << " ---" << c <> N >> M && N && M){
		init();
    	for (int i = 1; i <= N; ++i) {
    		for(int j = 1; j <= M; ++j) {
    			cin >> ch;
				if(ch == 'H'){
					Peo[CntPeo].x = i;
					Peo[CntPeo++].y = j;
				} 
				if(ch == 'm'){
					Home[CntHome].x = i;
					Home[CntHome++].y = j;
				}
    		}	
    	}
    	for(int i = 1; i < CntPeo; ++i) {
        	G[i].clear();
    	}
    	for(int i = 1; i < CntPeo; ++i) {
    		for(int j = 1; j < CntHome; ++j) {
    			int c = Distance(Peo[i], Home[j]);
    			G[i].push_back(make_pair (j, -c) );
    			//cout << i <<  " " << j  << "="<< c << endl;
    		}
    	}
    	cout << KM() << endl;
    }
    return 0;
}

费用流AC:
 

#include
#include
#include
#include
#include
#include
#include 
using namespace std;
int N, M; 
char G[150][150];
struct Point{
	int x, y;
};
const int maxn = 505;
const int inf = 0x3f3f3f3f;
int path[maxn], dis[maxn], head[maxn], vis[maxn], cnt;
void init() {
	cnt = 0;
	memset(head, -1, sizeof(head));
}
struct node{
	int v, flow, cost, nex;
}edge[maxn * maxn];
void addEdge(int u, int v, int flow, int cost) {
	edge[cnt] = {v, flow, cost, head[u]};
	head[u] = cnt++;
	edge[cnt] = {u, 0, -cost, head[v]};
	head[v] = cnt++;
}
int Spfa(int s, int t) {
	memset(vis, 0, sizeof(vis));
	memset(dis, inf, sizeof(dis));
	memset(path, -1, sizeof(path));
	queue que;
	que.push(s);
	dis[s] = 0;
	vis[s] = 1;
	while(!que.empty()) {
		int u = que.front();
		que.pop();
		vis[u] = 0;
		for(int i = head[u]; i != -1; i = edge[i].nex){
			int v = edge[i].v;
			int flow = edge[i].flow;
			int cost = edge[i].cost;
			if (flow > 0 && dis[v] > dis[u] + cost) {
				dis[v] = dis[u] + cost;
				path[v] = i;
				if(vis[v]) continue;
				vis[v] = 1;
				que.push(v);
			}
		}
	}
	return dis[t] != inf;
}
int MCMF(int s, int t, int &cost) {
	int maxflow = 0;
	while(Spfa(s, t)) {
		int flow = inf;
		for (int i = path[t]; i != -1; i = path[edge[i ^ 1].v]) {
			flow = min(flow, edge[i].flow);
		}
		for (int i = path[t]; i != -1; i = path[edge[i^1].v]) {
			edge[i].flow -= flow;
			edge[i^1].flow += flow;
			cost += flow * edge[i].cost;
		}
		maxflow += flow;
	}
	return maxflow;
}
int Distance(Point a, Point b) {
	return fabs(a.x - b.x) + fabs(a.y - b.y);
} 
int main () {
	Point People[maxn], House[maxn];
	while(~scanf("%d%d", &N, &M) && N + M){
		init();
		for(int i = 0; i < N; ++i) {
			scanf("%s", G[i]);
		}
		int CntP = 1;
		int CntH = 1;
		for (int i = 0; i < N; ++i) {
			for (int j = 0; j < M; ++j) {
				if(G[i][j] == 'm'){
					People[CntP].x = i;
					People[CntP].y = j;
					CntP++;
				}	
				else if(G[i][j] == 'H') {
					House[CntH].x = i;
					House[CntH].y = j;
					CntH++;
				}
			}
		}
		for (int i = 1; i < CntP; ++i) {
			for (int j = 1; j < CntH; ++j) {
				int dis = Distance(People[i], House[j]);
				addEdge(i, j + 100, 1, dis);	
			}
		}
		for(int i = 1; i < CntP; ++i) {
			addEdge(0, i, 1, 0);
		}
		for(int j = 1; j < CntH; ++j) {
			addEdge(j + 100,  201, 1, 0);
		}
		int Cost = 0;
		int Ans = MCMF(0, 201, Cost);
		printf("%d\n", Cost);
	}
	return 0;
} 

 

你可能感兴趣的:(KM算法,费用流)