网络流之最小费用最大流之 D - Going Home POJ - 2195

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wuxiaowu547/article/details/82118891

题目链接
建图:
源点到人的费用为0容量为1;
每个人到每个房子建一条边,费用为这个房子到这个人的距离,容量为1;
房子到终点的费用为0容量为1;

做这个题时,找了半天bug,首先注意房子和人的个数不是n,误以为n,调错了好久,还有sum,num的初始化,一开始放错位置了,还有就是存房子和人的位置时,存错了;

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define M 1100
const int inf=0x3f3f3f3f;
int n,m;
struct node
{
    int u,v,c,f,next;  //C为花费,F为flow流量
} e[M*40];


struct point
{
    int x,y;
} a[500],b[500];


int pre[M],dis[M],head[M],t;
int vis[M];
char mmap[500][500];
void add1(int u,int v,int c,int f)
{
    e[t].u=u;
    e[t].v=v;
    e[t].c=c;
    e[t].f=f;
    e[t].next=head[u];
    head[u]=t++;
}


void add(int u,int v,int c,int f)//费用,流量
{
    add1(u,v,c,f);
    add1(v,u,-c,0);  //反向边流量初始为零,如果走反向边费用正好和原边抵消
}


int spfa(int s,int t)
{
    int i,u,v;
    queue<int>q;
    q.push(s);
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    for(i=s; i<=t; i++)
        dis[i]=inf;
    dis[s]=0;
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(i=head[u]; i!=-1; i=e[i].next)
        {
            v=e[i].v;
            if(e[i].f&&dis[v]>dis[u]+e[i].c)  //找到一条最小费用流
            {
                dis[v]=dis[u]+e[i].c;
                pre[v]=i;       //记录路径
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
        vis[u]=0;
    }
    if(dis[t]!=inf)
        return 1;
    return 0;
}


void solve(int s,int t)
{
    int ans=0,i,j;
    int flow=0,cost=0;     //总流量、总费用
    while(spfa(s,t))
    {
        int minf=inf;
        for(i=pre[t]; i!=-1; i=pre[e[i].u])
        {
            if(e[i].f<minf)
                minf=e[i].f;
        }
        flow+=minf;   //该条路径的流量
        for(i=pre[t]; i!=-1; i=pre[e[i].u])
        {
            j=i^1;
            e[i].f-=minf;
            e[j].f+=minf;
        }
        cost+=dis[t]*minf;   //单位运费和乘以流量得费用
    }
    printf("%d\n",cost);
}


int main()
{

    while(~scanf("%d%d",&n,&m)&&(n||m))
    {
        t=0;
        int sum=1,num=1;
        memset(head,-1,sizeof(head));
        for(int i=1; i<=n; i++)
        {
            scanf("%s",mmap[i]+1);
        }
//        for(int i=1;i<=n;i++)
//        {
//            for(int j=1;j<=m;j++)
//            {
//                printf("%c",mmap[i][j]);
//            }
//            printf("\n");
//        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                if(mmap[i][j]=='m')
                {
                    a[sum].x=i;
                    a[sum].y=j;
                    sum++;
                }
                if(mmap[i][j]=='H')
                {
                    b[num].x=i;
                    b[num].y=j;
                    num++;
                }
            }
        }


        int s=0,tt=sum-1+num-1+1;
        for(int i=1; i<sum; i++)   //i,人,j+n,房子
        {
            for(int j=1; j<num; j++)
            {

                int dis=abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y);
                add(i,j+sum-1,dis,1);
            }
        }
        for(int i=1; i<sum; i++)
        {
            add(s,i,0,1);
        }
        for(int i=1; i<num; i++)
        {
            add(i+sum-1,tt,0,1);
        }
        solve(s,tt);
    }


}

猜你喜欢

转载自blog.csdn.net/wuxiaowu547/article/details/82118891