Poj 2195 Going Home

题目链接:ヾ(≧∇≦*)ゝ

题意:有n*m的矩阵,H表示这个点是一个房子,m表示这个点是一个人,现在每一个人需要走入一个房间,已经知道的是
认得数目和房子的个数一定是相同的,现在问这些人都回到一个房间所走的总的步数最小

Solution:

\(2\le n\le100,2\le m\le100\),费用流

把所有的人和房子连边,容量为1,费用为需要的步数

把源点与人连边,容量为1,费用为0,汇点与房子连边,容量为1,费用为0

需要解释的是为什么汇点与房子连的边容量为1,这是因为每个房子只能住一个人

最后一遍费用流得出答案。本题有多组数据,读入到0结束。

Code:

#include<queue>
#include<cstdio>
#include<ctype.h>
#include<cstring>
#include<algorithm>
#define N 50001
#define inf 1926081700
using namespace std;
typedef pair<int,int> pii;
int n,m,cnt=1,t;
int S,T,head[N],per[N];
char mp[101][101];
struct Edge{int nxt,to,v,w;}edge[N];
void ins(int x,int y,int z,int w){
	edge[++cnt].nxt=head[x];
	edge[cnt].to=y;edge[cnt].v=z;
	edge[cnt].w=w;head[x]=cnt;
}
namespace Network_Flow{
	queue<int> q;
	int delta,maxflow,mincost;
	int vis[N],pre[N],dis[N];
	int spfa(){
		delta=inf;pre[T]=0;
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=T;i++) dis[i]=inf;
		q.push(S);vis[S]=1;dis[S]=0;
		while(!q.empty()){
			int x=q.front();q.pop();vis[x]=0;
			for(int i=head[x];i;i=edge[i].nxt){
				int y=edge[i].to;
				if(edge[i].v&&dis[x]+edge[i].w<dis[y]){
					dis[y]=edge[i].w+dis[x];
					delta=min(delta,edge[i].v);
					pre[y]=i;if(!vis[y]) q.push(y),vis[y]=1;
				}
			}
		}
		return pre[T];
	}
	void update(){
		int x=T;
		while(x!=S){
			int u=pre[x];
			edge[u].v-=delta;
			edge[u^1].v+=delta;
			x=edge[u^1].to;
		}
		maxflow+=delta;mincost+=dis[T];
	}
	void Edmonds_Karp(){
        mincost=maxflow=0;
		while(spfa()) update();
		printf("%d\n",mincost);
	}
}
void format(){
    cnt=1;t=0;
    memset(head,0,sizeof(head));
    memset(edge,0,sizeof(edge));
}
int num(int i,int j){return (i-1)*m+j;}
pii pos(int x){return make_pair(x/m+(x%m!=0),(x%m==0)?m:x%m);}
int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int main(){
	using namespace Network_Flow;
	begin:n=read();m=read();
    if(n==0||m==0) return 0;
    S=n*m+1;T=S+1;format();
    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'){
                int x=num(i,j);
                per[++t]=num(i,j);
                ins(S,x,1,0);ins(x,S,0,0);
            }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(mp[i][j]=='H'){
                int x=num(i,j);
                for(int k=1;k<=t;k++){
                    pii tmp=pos(per[k]);
                    int w=abs(tmp.first-i)+abs(tmp.second-j);
                    ins(per[k],x,1,w);ins(x,per[k],0,-w);
                }
                ins(x,T,1,0);ins(T,x,0,0);
            }
    Edmonds_Karp();goto begin;
}
posted @ 2019-01-31 18:37  DQY_dqy  阅读(112)  评论(0编辑  收藏  举报