1. 程式人生 > >[poj] 2195 Going Home || 最小費用最大流

[poj] 2195 Going Home || 最小費用最大流

etc 移動 數量 print getc truct pop namespace -c

原題

給定一個N*M的地圖,地圖上有若幹個人和房子,且人與房子的數量一致。人每移動一格需花費1(即單位費用=單位距離),一間房子只能入住一個人。現在要求所有的人都入住,求最小費用。

把每個人和每個房子連費用為距離,容量為1的邊就可以了。

#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#define N 220
#define inf 0x3f3f3f3f
using namespace std;
int n,m,head[N],dis[N],cur[N],ans,cnt=2
,s,t,ANS,T,cse,xm[110],ym[110],xh[110],yh[110],man,house; queue <int> q; char a; bool vis[N]; struct hhh { int to,next,w,cost; }edge[50005]; int read() { int ans=0,fu=1; char j=getchar(); for (;(j<'0' || j>'9') && j!='-';j=getchar()) ; if (j=='-'
) fu=-1,j=getchar(); for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0'; return ans*fu; } void add(int u,int v,int w,int c) { edge[cnt].to=v; edge[cnt].w=w; edge[cnt].next=head[u]; edge[cnt].cost=c; head[u]=cnt++; } void addEdge(int
u,int v,int w,int c) { add(u,v,w,c); add(v,u,0,-c); } bool bfs() { for (int i=s;i<=t;i++) vis[i]=0,cur[i]=head[i],dis[i]=inf; q.push(s); dis[s]=0; vis[s]=1; while(!q.empty()) { int r=q.front(); q.pop(); vis[r]=0; for (int i=head[r],v;i;i=edge[i].next) { v=edge[i].to; if (edge[i].w>0 && dis[r]+edge[i].cost<dis[v]) { dis[v]=dis[r]+edge[i].cost; if (!vis[v]) { vis[v]=1; q.push(v); } } } } return dis[t]!=inf; } int dfs(int x,int f) { if (x==t) return ANS+=f*dis[t],f; int ha=0,now; vis[x]=1; for (int &i=cur[x],v;i;i=edge[i].next) { v=edge[i].to; if (vis[v]) continue; if (edge[i].w>0 && dis[v]==dis[x]+edge[i].cost) { now=dfs(v,min(f-ha,edge[i].w)); if (now) { ha+=now; edge[i].w-=now; edge[i^1].w+=now; } } if (ha==f) return ha; } return ha; } void init() { memset(head,0,sizeof(head)); cnt=2; ANS=0; ans=0; man=0; house=0; } int main() { while (~scanf("%d%d",&n,&m)) { if (!n && !m) break; init(); s=0; for (int i=1;i<=n;i++) { getchar(); for (int j=1;j<=m;j++) { a=getchar(); if (a=='m') xm[++man]=i,ym[man]=j; else if (a=='H') xh[++house]=i,yh[house]=j; } } t=man+house+1; for (int i=1;i<=man;i++) addEdge(s,i,1,0); for (int i=1;i<=house;i++) addEdge(man+i,t,1,0); for (int i=1;i<=man;i++) for (int j=1;j<=house;j++) addEdge(i,man+j,1,abs(xh[j]-xm[i])+abs(yh[j]-ym[i])); while (bfs()) ans+=dfs(s,inf); printf("%d\n",ANS); } return 0; }

[poj] 2195 Going Home || 最小費用最大流