码迷,mamicode.com
首页 > 其他好文 > 详细

Poj 2195 Going Home

时间:2019-01-31 20:47:19      阅读:194      评论:0      收藏:0      [点我收藏+]

标签:turn   相同   ref   mem   sdi   个数   cond   struct   pop   

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

题意:有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;
}

Poj 2195 Going Home

标签:turn   相同   ref   mem   sdi   个数   cond   struct   pop   

原文地址:https://www.cnblogs.com/NLDQY/p/10343168.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!