POJ_2195_Going Home

题意:用'H','m','.'作出矩阵,'H'代表房子,'m'代表人,人一次只能水平或者垂直移动到相邻的点,问所有人一共走的步数的最小值。

分析:明显的求二分图最大权匹配。KM算法求得的是最大权匹配,而题中要求的是最小值,所以要将边的权值以其负值储存。

  有一点需要注意:link数组(匹配数组)必须初始化为-1,如果初始化为0,则link[0]=0,则默认第0个人与第0个房子匹配,在执行匈牙利算法是就会出错,找到错误的增广路,第一次提交就错在这。

总结:基本能只用KM算法,熟练度还有待增强。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<stdlib.h>
using namespace std;
#define Del(x,y) memset(x,y,sizeof(x))
#define N 105

struct Point
{
    int x,y;
};
Point house[N];
Point man[N];

int n,m;
int cnth,cntm;
int lx[N],ly[N],link[N],w[N][N];
bool S[N],T[N];
char grid[N];

int dis(Point a,Point b)
{
    return (abs(a.x-b.x)+abs(a.y-b.y));
}
void update()
{
    int a=99999999;
    for(int i=0; i<cnth; i++)
        if(S[i])
            for(int j=0; j<cntm; j++)
                if(!T[j])
                    a=min(a,lx[i]+ly[j]-w[i][j]);
    for(int i=0; i<cnth; i++)
    {
        if(S[i])
            lx[i]-=a;
        if(T[i])
            ly[i]+=a;
    }
}

bool match(int i)
{
    S[i]=true;
    for(int j=0; j<cntm; j++)
        if(lx[i]+ly[j]-w[i][j]==0&&!T[j])
        {
            T[j]=true;
            if(link[j]==-1||match(link[j]))
            {
                link[j]=i;
                return true;
            }
        }
    return false;
}

void KM()
{
    Del(link,-1);    ///必须初始化为-1,如果初始化为0,则link[0]=0,则默认第0个人与第0个房子匹配,在执行匈牙利算法是就会出错,找到错误的增广路
    for(int i=0; i<cnth; i++)
    {
        lx[i]=ly[i]=0;
        for(int j=0; j<cntm; j++)
            lx[i]=max(lx[i],w[i][j]);
    }
    for(int i=0; i<cnth; i++)
        for(;;)
        {
            Del(S,0);
            Del(T,0);
            if(match(i))
                break;
            else
                update();
        }
}

int main()
{
    while(~scanf("%d%d",&n,&m)&&n!=0)
    {
        cntm=cnth=0;
        for(int i=0; i<n; i++)
        {
            scanf("%s",grid);
            for(int j=0; j<m; j++)
            {
                if(grid[j]=='H')
                {
                    house[cnth].x=i;
                    house[cnth].y=j;
                    cnth++;
                }
                if(grid[j]=='m')
                {
                    man[cntm].x=i;
                    man[cntm].y=j;
                    cntm++;
                }
            }
        }
        for(int i=0; i<cnth; i++)
            for(int j=0; j<cntm; j++)
                w[i][j]=-dis(house[i],man[j]);
        KM();
        int ans=0;
        for(int i=0; i<cntm; i++)
            ans+=dis(house[link[i]],man[i]);
        printf("%d\n",ans);
    }
    return 0;
}

 

posted on 2015-08-28 21:37  JASONlee3  阅读(195)  评论(0编辑  收藏  举报

导航