POJ - 2195 Going Home 【最小費用流】

題意:n*m的地圖有人和房子,要讓每個人進入一個房子(每個房子只能進入一個人,人可以走任何地方(可以經過房子也可以多

人在一個位置,每個人走一步花費1美元,求最小的花費。

思路:最小費用流模板,建好圖。。抄模板就行了,這個圖比較好建。

原點0~(1~k)房子~(k+1~k+kk)人~(k+kk+1)結點

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#define N 100000
#define INF 0x3fffffff
using namespace std;
char mp[106][106];
typedef pair<int ,int >P;
struct edge
{
	int to,cap,cost,rev;
};
int V;
vector <edge> G[N];
int h[N];
int dist[N];
int prevv[N],preve[N];
void add(int from,int to,int cap,int cost)
{
	G[from].push_back((edge){to,cap,cost,G[to].size()});
	G[to].push_back((edge){from,0,-cost,G[from].size()-1});
}
int min_cost_flow(int s,int t,int f)
{
	int res=0;
	fill(h,h+V,0);
	while(f>0)
	{
		priority_queue<P,vector<P>, greater<P> > que;
		fill(dist,dist+V,INF);
		dist[s]=0;
		que.push(P(0,s));
		while(!que.empty())
		{
			P p=que.top();que.pop();
			int v=p.second;
			if(dist[v]<p.first) continue;
			for(int i=0;i<G[v].size();i++)
			{
				edge &e=G[v][i];
				if(e.cap>0&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to])
				{
					dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
					prevv[e.to]=v;
					preve[e.to]=i;
					que.push(P(dist[e.to],e.to));
				}
			}
		}
		if(dist[t]==INF)
		{
			return -1;
		}
		for(int v=0;v<V;v++)
		h[v]+=dist[v];
		int d=f;
		for(int v=t;v!=s;v=prevv[v])
		{
			d=min(d,G[prevv[v]][preve[v]].cap);
		}
		f-=d;
		res+=d*h[t];
		for(int v=t;v!=s;v=prevv[v])
		{
			edge &e=G[prevv[v]][preve[v]];
			e.cap-=d;
			G[v][e.rev].cap+=d;
		}
	}
	return res;
}
struct nomd
{
	int x,y;
}w[100000];
nomd ww[100000];
int ta(int a,int b)
{
	return fabs(w[a].x-ww[b].x)+abs(w[a].y-ww[b].y);
}
int main()
{
	int n,m;
	while(scanf("%d %d",&n,&m)) 
	{
		memset(mp,0,sizeof(mp));
		if(n==0&&m==0)
		break;
		for(int i=0;i<n;i++)
		scanf("%s",mp[i]);
		int k=0,kk=0;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(mp[i][j]=='H')
				{
					w[++k].x=i;w[k].y=j;
					add(0,k,1,0);
				}
			}
		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(mp[i][j]=='m')
				{
					ww[++kk].x=i,ww[kk].y=j;
				}
			}
		}
		for(int i=1;i<=kk;i++)
		{
			add(k+i,k+kk+1,1,0);
		}
		for(int i=1;i<=k;i++)
		{
			for(int j=1;j<=kk;j++)
			{
				add(i,k+j,1,ta(i,j));
			}
		}
		V=k+kk+1+1;
		printf("%d\n",min_cost_flow(0,k+kk+1,kk));
		for(int i=0;i<=k+kk+1;i++)
		G[i].clear();
		memset(w,0,sizeof(w));
		memset(ww,0,sizeof(ww));
		memset(prevv,0,sizeof prevv);
		memset(preve,0,sizeof(preve));
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章