poj 2195 最小费用最大流 EK+SPFA

来源:互联网 发布:手机不休眠软件 编辑:程序博客网 时间:2024/06/06 12:50

传送门

题意:给你一个矩阵,里面有数量相等的H和m,代表房子和人,每个人要找个房子,一个人到一个房子的费用是他走的步数,一个房子只能容纳一个人,求所有人都到房子的最小费用。

个人心得:第一次做最小费用最大流,原本不会费用流的,借着这题就是想学习一下,网上各种博客讲的都好神啊。由于本人最大流只会EK算法(最慢的),所以对于网上大牛的博客各种看不懂,直到看到了这个,里面说就是把EK算法的BFS过程改成SPFA,于是顿悟,好吧,就是这点差别。我理解了下她的代码,然后完成了人生第一道费用流。不过目前掌握的算法效率不高,有待学习新的算法。

思路:感觉没啥好说的,主要就是建图,添加超级源点和汇点,然后就是按照EK+SPFA的思路做了。


#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<cmath>#define maxn 2000using namespace std;int m,n;int hnum,mnum,hx[200],hy[200],mx[200],my[200];int c[210][210],cost[210][210],f[210][210],d[210],pre[210];bool v[210];char str[200];int abs(int x){    return x>0?x:-x;}int EK(int s,int t){    int ans=0;    memset(f,0,sizeof(f));    memset(v,0,sizeof(v));    queue<int>q;    while(1)    {        for(int i=0;i<=t;i++)d[i]=maxn;        d[s]=0;        q.push(s);        v[s]=1;        while(!q.empty())        {            int a=q.front();            q.pop();            v[a]=0;            for(int i=s;i<=t;i++)            {                if(c[a][i]-f[a][i]>0&&d[i]>d[a]+cost[a][i])                {                    pre[i]=a;                    d[i]=d[a]+cost[a][i];                    if(!v[i])                    {                        q.push(i);                        v[i]=1;                    }                }            }        }        if(d[t]==maxn)break;        int mi=maxn;        for(int i=t;i!=s;i=pre[i])        {            if(c[pre[i]][i]-f[pre[i]][i]<mi)mi=c[pre[i]][i]-f[pre[i]][i];        }        for(int i=t;i!=s;i=pre[i])        {            f[pre[i]][i]+=mi;            f[i][pre[i]]-=mi;            ans+=cost[pre[i]][i];        }    }    return ans;}int main(){    while(scanf("%d%d",&m,&n)&&n&&m)    {        hnum=mnum=0;        memset(c,0,sizeof(c));        memset(cost,0,sizeof(cost));        for(int i=0;i<m;i++)        {            scanf("%s",str);            for(int j=0;j<n;j++)            {                if(str[j]=='H')                {                    hx[++hnum]=i;                    hy[hnum]=j;                }                else if(str[j]=='m')                {                    mx[++mnum]=i;                    my[mnum]=j;                }            }        }        for(int i=1;i<=mnum;i++)        {            c[0][i]=1;            for(int j=1;j<=hnum;j++)            {                int hh=mnum+j;                c[i][hh]=1;                cost[i][hh]=abs(mx[i]-hx[j])+abs(my[i]-hy[j]);                cost[hh][i]=-cost[i][hh];            }        }        for(int i=1;i<=hnum;i++)        {            c[i+mnum][hnum+mnum+1]=1;        }        printf("%d\n",EK(0,hnum+mnum+1));    }    return 0;}


原创粉丝点击