http://acm.hdu.edu.cn/showproblem.php?pid=1533
2 2 .m H. 5 5 HH..m ..... ..... ..... mm..H 7 8 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 0 0
2 10 28
对于图中的x个人和x个房子,要求用最小的时间让每个人都进入房内,人到房间的距离定义为曼哈顿距离
算法:最小费用流,让源点和人建边,流量为1,费用为0,让房间和汇点建边,流量为1,费用为0,让人和房子两两建边,流量为inf,费用为曼哈顿距离;
程序:
#include"string.h" #include"stdio.h" #include"iostream" #include"queue" #define M 10009 #define inf 999999999 using namespace std; struct node { int x,y; }house[M],men[M]; struct st { int u,v,w,cost,next; }edge[M*10]; int head[M],t,use[M],dis[M],pre[M]; int Fabs(int x) { if(x<0) x=-x; return x; } void init() { t=0; memset(head,-1,sizeof(head)); } void add(int u,int v,int w,int cost) { edge[t].u=u; edge[t].v=v; edge[t].w=w; edge[t].cost=cost; edge[t].next=head[u]; head[u]=t++; edge[t].u=v; edge[t].v=u; edge[t].w=0; edge[t].cost=-cost; edge[t].next=head[v]; head[v]=t++; } int min_flow(int S,int T) { int ans=0; while(1) { int i; queue<int>q; for(i=0;i<=T;i++) dis[i]=inf; dis[S]=0; memset(use,0,sizeof(use)); memset(pre,-1,sizeof(pre)); q.push(S); while(!q.empty()) { int u=q.front(); use[u]=0; q.pop(); for(i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(edge[i].w&&dis[v]>dis[u]+edge[i].cost) { dis[v]=dis[u]+edge[i].cost; pre[v]=i; if(!use[v]) { use[v]=1; q.push(v); } } } } if(dis[T]==inf) break; int Min=inf+1; for(i=pre[T];i!=-1;i=pre[edge[i].u]) { Min=min(Min,edge[i].w); } for(i=pre[T];i!=-1;i=pre[edge[i].u]) { edge[i].w-=Min; edge[i^1].w+=Min; } ans+=Min*dis[T]; } return ans; } int main() { int n,m,i,j; char mp[111][111]; while(scanf("%d%d",&n,&m),m||n) { int hh=0,mm=0; for(i=0;i<n;i++) { scanf("%s",mp[i]); for(j=0;j<m;j++) { if(mp[i][j]=='m') { mm++; men[mm].x=i; men[mm].y=j; } if(mp[i][j]=='H') { hh++; house[hh].x=i; house[hh].y=j; } } } init(); for(i=1;i<=mm;i++) add(0,i,1,0); for(i=1;i<=hh;i++) add(i+mm,hh+mm+1,1,0); for(i=1;i<=mm;i++) { for(j=1;j<=hh;j++) { add(i,mm+j,inf,Fabs(men[i].x-house[j].x)+Fabs(men[i].y-house[j].y)); } } int ans=min_flow(0,mm+hh+1); printf("%d\n",ans); } return 0; }