POJ 2195 Going Home | 带权二分图匹配
给个地图有人和房子
保证人==房子,每个人移动到房子处需要花费曼哈顿距离的代价
问让人都住在房子里最小代价
显然是个带权二分图最大匹配
转化成以一个网络,规定w是容量,c是代价
1.S向人连边,w=1,c=0
2.房子向T连边,w=1,c=0
3.人向房子连边 w=1,c=距离
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<vector> #define N 10000 #define INF 1000000000 using namespace std; deque <int> q; int head[N],lev[N],dist[N],n,m,ecnt=1,vis[N],S,T,ans,H,M; char mp[110][110]; struct adj { int nxt,v,w,c; }e[200*200]; int Abs(int x) {return x>0?x:-x;} struct coor { int x,y; int operator - (const coor &a)const {return Abs(x-a.x)+Abs(y-a.y);} }; coor make(int x,int y) { coor ret; ret.x=x,ret.y=y; return ret; } vector <coor> house,man; inline void add(int u,int v,int w,int c) { e[++ecnt].v=v,e[ecnt].w=w,e[ecnt].c=c,e[ecnt].nxt=head[u],head[u]=ecnt; e[++ecnt].v=u,e[ecnt].w=0,e[ecnt].c=-c,e[ecnt].nxt=head[v],head[v]=ecnt; } inline int spfa(int s,int t) { int v; memset(vis,0,sizeof(vis)); for (int i=s;i<=t;i++) dist[i]=INF; dist[t]=0,vis[t]=1; q.push_back(t); while (!q.empty()) { int u=q.front();q.pop_front(); for (int i=head[u];i;i=e[i].nxt) if (e[i^1].w>0 && dist[v=e[i].v]>dist[u]-e[i].c) { dist[v]=dist[u]-e[i].c; if (!vis[v]) { vis[v]=1; if (!q.empty() && dist[v]<dist[q.front()]) q.push_front(v); else q.push_back(v); } } vis[u]=0; } return dist[s]<INF; } inline int dfs(int x,int flow) { if (x==T) return vis[T]=1,flow; int used=0,tmp,v; vis[x]=1; for (int i=head[x];i;i=e[i].nxt) if (!vis[v=e[i].v] && e[i].w>0 && dist[x]-e[i].c==dist[v]) { tmp=dfs(v,min(e[i].w,flow-used)); if (tmp>0) ans+=tmp*e[i].c,e[i].w-=tmp,e[i^1].w+=tmp,used+=tmp; if (used==flow) break; } return used; } inline int CostFlow() { int Flow=0; while (spfa(S,T)) { vis[T]=1; while (vis[T]) { memset(vis,0,sizeof(vis)); Flow+=dfs(S,INF); } } return Flow; } void init() { memset(head,0,sizeof(head)); man.clear(); house.clear(); ans=M=H=0; ecnt=1; } int main() { while (scanf("%d%d",&n,&m)!=EOF) { if (n==0 && m==0) break; init(); for (int i=1;i<=n;i++) scanf("%s",mp[i]+1); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (mp[i][j]=='m') man.push_back(make(i,j)),M++; else if (mp[i][j]=='H') house.push_back(make(i,j)),H++; T=H+M+1; for (int i=0;i<M;i++) for (int j=0;j<H;j++) add(i+1,M+j+1,1,man[i]-house[j]); for (int i=1;i<=M;i++) add(S,i,1,0); for (int i=1;i<=H;i++) add(M+i,T,1,0); CostFlow(); printf("%d\n",ans); } return 0; }