POJ 2195 Going Home(最小费用最大流)

http://poj.org/problem?id=2195

题意 :  N*M的点阵中,有N个人,N个房子。让x个人走到这x个房子中,只能上下左右走,每个人每走一步就花1美元,问当所有的人都归位了之后,需要花多少美元。

思路 :最小费用最大流。把人作为一个顶点集合U,房子作为另一个顶点集合V,把U中所有点到V中所有点连线,费用cost[u][v]为abs(△x)+abs(△y),反向弧费用cost[v][u]= -cost[u][v],容量cap[u][v]=1,构成一个多源多汇的二分图。 由于每一个多源多汇的网络流都必有一个与之对应的单源单汇的网络流,为了便于解题,由此构造一个超级源s和超级汇t,超级源s与U中所有点相连,费用cost[s][u]=0(这是显然的),容量cap[s][u]=1;V中所有点与超级汇t相连,费用cost[v][t]=0(这是显然的),容量cap[t][v]=1。至于其他不连通的点,费用与容量均为0。容量为0的边,可以理解为饱和边,不再连通。而上述的所有边之所以容量初始化为1,是因为每间房子只允许入住1个人。而与超级源(汇)相连的边的费用之所以为0,是为了现在所构造的单源单汇网络流最终所求的最小费用等于原来的多源多汇网络流的最小费用。

#include <iostream>

#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <queue>

#include <math.h>



using namespace std;



const int maxn = 210 ;

struct node

{

    int u ;

    int v ;

}p[210],h[210] ;



int pre[maxn],dist[maxn],n,m,pn,hn,s,t,cnt;

int cap[maxn][maxn],flow[maxn][maxn],cost[maxn][maxn] ;

bool flag[maxn] ;

char ch[maxn][maxn] ;



const int INF = 1000000000;



void Init()

{

    pn = hn = 0 ;

    cnt = s = 0 ;

    memset(cap,0,sizeof(cap)) ;

    memset(flow,0,sizeof(flow)) ;

    memset(cost,0,sizeof(cost)) ;

}

void spfa()

{

    queue<int>Q ;

    for(int i = 0 ; i < maxn ; i++)

        dist[i] = INF ;

    memset(pre,-1,sizeof(pre)) ;

    memset(flag,false,sizeof(flag)) ;

    Q.push(s) ;

    flag[s] = true ;

    dist[s] = 0 ;

    while(!Q.empty())

    {

        int u = Q.front() ;

        Q.pop() ;

        flag[u] = false ;

        for(int v = 0 ; v <= t ; v++)

        {

            if(cap[u][v] && dist[v] > dist[u] + cost[u][v])

            {

                dist[v] = dist[u] + cost[u][v] ;

                pre[v] = u ;

                if(!flag[v])

                {

                    Q.push(v) ;

                    flag[v] = true ;

                }

            }

        }

    }

}



void mcmf()

{

    for( ; ; )

    {

        spfa() ;

        if(pre[t] == -1) break ;//没有父节点了,

        int x = t ,minn = INF ;

        while(pre[x] != -1)

        {

            minn = min(minn,cap[pre[x]][x]) ;

            x = pre[x] ;

        }

        x = t ;

        while(pre[x] != -1)

        {

            cap[pre[x]][x] -= minn ;

            cap[x][pre[x]] += minn ;

            cnt += minn*cost[pre[x]][x];

            x = pre[x];

        }

    }



}



int main()

{

    while(scanf("%d %d",&n,&m) != EOF)

    {

        if(n == 0 && m == 0) break ;

        Init() ;

        for(int i = 0 ; i < n ; i++)

        {

            scanf("%s",ch[i]) ;

            for(int j = 0 ; j < m ; j++)

            {

                if(ch[i][j] == 'H')

                {

                    h[++hn].u = i ;

                    h[hn].v = j ;

                }

                else if(ch[i][j] == 'm')

                {

                    p[++pn].u = i ;

                    p[pn].v = j ;

                }

            }

        }

        t = pn+hn+1 ;

        for(int i = 1 ; i <= pn ; i++)

        cap[s][i] = 1 ;

        for(int i = 1 ; i <= hn ; i++)

        cap[i+pn][t] = 1 ;

        for(int i = 1 ; i <= pn ; i++)

        {

            for(int j = 1 ; j <= hn ; j++)

            {

                cap[i][j+pn] = 1 ;

                cost[i][j+pn] = fabs(p[i].u-h[j].u) + fabs(p[i].v-h[j].v) ;

                cost[j+pn][i] = -cost[i][j+pn] ;

            }

        }

        mcmf() ;

        printf("%d\n",cnt) ;

    }

    return 0;

}
View Code

 

你可能感兴趣的:(home)