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;
}

 

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