POJ-2195 Going Home
阿新 • • 發佈:2018-11-10
將題目轉化為最小費用最大流問題
在每個人和房子之間建邊,容量為1,cost為兩點之間的曼哈頓距離
然後源點連向人,容量1,cost=0,房子連向匯點,容量1,cost=0
從源點到匯點跑一遍演算法就得到答案
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; typedef long long ll; const int N=200+10; const int M=3e4+10; const int INF=0x7f7f7f7f; struct Edge { int to,nxt,cap,flow,cost; }edge[M]; int tot,first[N]; void addedge(int u,int v,int w,int rw,int cost) { edge[tot].to=v;edge[tot].cap=w;edge[tot].flow=0; edge[tot].cost=cost;edge[tot].nxt=first[u];first[u]=tot++; edge[tot].to=u;edge[tot].cap=rw;edge[tot].flow=0; edge[tot].cost=-cost;edge[tot].nxt=first[v];first[v]=tot++; } void init() { tot=0; memset(first,-1,sizeof(first)); } int pre[N],dis[N]; bool vis[N]; bool spfa(int s,int t,int n) { queue<int> q; for(int i=0;i<n;i++) { dis[i]=INF; pre[i]=-1; vis[i]=false; } dis[s]=0; vis[s]=true; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=false; for(int i=first[u];i!=-1;i=edge[i].nxt) { int v=edge[i].to; if(edge[i].cap>edge[i].flow&&edge[i].cost+dis[u]<dis[v]) { dis[v]=edge[i].cost+dis[u]; pre[v]=i; if(!vis[v]) { vis[v]=true; q.push(v); } } } } if(pre[t]==-1) return false; else return true; } int MCMF(int s,int t,int &cost,int n) { int flow=0; cost=0; while(spfa(s,t,n)) { int Min=INF; for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]) if(Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]) { edge[i].flow+=Min; edge[i^1].flow-=Min; cost+=edge[i].cost*Min; } flow+=Min; } return flow; } int x[N],y[N]; char g[N][N]; int main() { int n,m; while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0) break; init(); int cnt=0,cnt0; for(int i=0;i<n;i++) scanf("%s",g[i]); for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(g[i][j]=='H') { cnt++; x[cnt]=i; y[cnt]=j; } for(int i=1;i<=cnt;i++) addedge(0,i,1,0,0); cnt0=cnt; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(g[i][j]=='m') { cnt0++; for(int k=1;k<=cnt;k++) addedge(k,cnt0,1,0,abs(i-x[k])+abs(j-y[k])); addedge(cnt0,2*cnt+1,1,0,0); } int cost; MCMF(0,2*cnt+1,cost,2*cnt+2); printf("%d\n",cost); } return 0; }