zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    冒泡排序法
    选择排序法
    pyhanlp 停用词与用户自定义词典
    pyhanlp 分词与词性标注
    第八九章 正态分布与超越正态
    深入浅出统计学第七章 几何分布,二项分布,柏松分布
    深入浅出统计学 第六章 排列与组合
    深入浅出统计学 第四五章 离散概率的计算与分布
    R语言简介与案例
    深入浅出统计学 第二三章 量度
  • 原文地址:https://www.cnblogs.com/jasonlixuetao/p/4767947.html
Copyright © 2011-2022 走看看