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

Going Home - poj 2195(网络流 | 二分匹配)

时间:2015-08-08 16:28:36      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:在一个网格里面有n个小男人和n个房子,现在想让每个小男人都有一个房子住,不过每个人移动一下都需要花费¥1,现在求出来最小的总花费。ps:可以认为网格的每个点都是很大的广场并且容纳所有的人,人可以走在有房子的点但是不进入房子。

分析:人-房子,很完美的带全都最小值匹配啊,人到一个房子的花费就是他们之间的曼哈顿距离,用这些距离构造一个二分图,然后用KM算法求出来最小费。下面是KM算法
***********************************************************************************************************************************************************************************
技术分享
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<math.h>
using namespace std;

const int MAXN = 107;
const int oo = 1e9+7;

struct point{int x, y;}man[MAXN], house[MAXN];
char G[MAXN][MAXN];
int w[MAXN][MAXN], slack[MAXN], Nx, Ny;
int dx[MAXN], dy[MAXN], Ly[MAXN];
bool vx[MAXN], vy[MAXN];

void InIt()
{
    Nx = Ny = 0;

    for(int i=1; i<MAXN; i++)
    {
        dx[i] = -oo;
        dy[i] = 0;
    }

}
bool Find(int i)
{
    vx[i] = true;
    for(int j=1; j<=Ny; j++)
    {
        if(!vy[j] && w[i][j] == dx[i]+dy[j])
        {
            vy[j] = true;
            if(!Ly[j] || Find(Ly[j]))
            {
                Ly[j] = i;
                return true;
            }
        }
        else if(!vy[j])
            slack[j] = min(slack[j], dx[i]+dy[j]-w[i][j]);
    }

    return false;
}
int KM()
{
    int i, j;

    memset(Ly, 0sizeof(Ly));

    for(i=1; i<=Nx; i++)
    {
        for(j=1; j<=Ny; j++)
            slack[j] = oo;
        while(true)
        {
            memset(vx, falsesizeof(vx));
            memset(vy, falsesizeof(vy));

            if(Find(i) == true)
                break;

            int d = oo;

            for(j=1; j<=Ny; j++)
            {
                if(!vy[j] && d > slack[j])
                    d = slack[j];
            }

            for(j=1; j<=Nx; j++)
            {
                if(vx[j])
                    dx[j] -= d;
            }
            for(j=1; j<=Ny; j++)
            {
                if(vy[j])
                    dy[j] += d;
                else
                    slack[j] -= d;
            }
        }
    }

    int sum = 0;

    for(i=1; i<=Ny; i++)
        sum += w[Ly[i]][i];

    return -sum;
}

int main()
{
    int M, N;

    while(scanf("%d%d", &M, &N), M+N)
    {
        int i, j;

        InIt();

        for(i=0; i<M; i++)
            scanf("%s", G[i]);

        for(i=0; i<M; i++)
        for(j=0; j<N; j++)
        {
            if(G[i][j] == m)
            {
                Nx++;
                man[Nx].x = i;
                man[Nx].y = j;
            }
            if(G[i][j] == H)
            {
                Ny++;
                house[Ny].x = i;
                house[Ny].y = j;
            }
        }

        for(i=1; i<=Nx; i++)
        for(j=1; j<=Ny; j++)
        {
            w[i][j] = fabs(man[i].x-house[j].x) + fabs(man[i].y-house[j].y);
            w[i][j] = -w[i][j];
            dx[i] = max(dx[i], w[i][j]);
        }

        printf("%d\n", KM());
    }

    return 0;
}
View Code

Going Home - poj 2195(网络流 | 二分匹配)

标签:

原文地址:http://www.cnblogs.com/liuxin13/p/4713278.html

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