当前位置:编程学习 > C/C++ >>

POJ 2195 Going Home(KM)- from lanshui_Yang

    题目大意:一张图中,有相等数量的“m” 和 “H” ,分别代表人和房子,要求通过移动人使最终每个房子里都有一个人,输出最小的移动步数。
        解题思路:这题是求最小权值匹配,可用KM算法求解,需要注意的是,KM算法求的是最大权值匹配,这里需要把每条边的权值取反,得到最大权值匹配后,再把答案取反。
 
        请看代码:
 
 
 
#include <set>  
#include <map>  
#include <stack>  
#include <cmath>  
#include <queue>  
#include <cstdio>  
#include <string>  
#include <vector>  
#include <iomanip>  
#include <cstring>  
#include <iostream>  
#include <algorithm>  
#define mem(a,b) memset(a,b,sizeof(a))  
#define INF 0x7fffffff  
using namespace std ;  
const int MAXN = 300 ;  
struct Node  
{  
    int x ;  
    int y ;  
} H[MAXN] , M[MAXN] ;  
int Lx[MAXN] , Ly[MAXN] ;  
bool visx[MAXN] , visy[MAXN] ;  
int yy[MAXN] ;  
int slack[MAXN] ;  
int w[MAXN][MAXN] ;  
char s[MAXN][MAXN] ;  
int n , m ;  
int mcnt , hcnt ;  
int ans ;  
void chu()  
{  
    mem(visx , 0) ;  
    mem(visy , 0) ;  
    mem(yy , -1) ;  
    mcnt = hcnt = 0 ;  
}  
void init()  
{  
    int i , j ;  
    for(i = 0 ; i < n ; i ++)  
    {  
        scanf("%s" , s[i]) ;  
        for(j = 0 ; j < m ; j ++)  
        {  
            if(s[i][j] == 'm')  
            {  
                M[mcnt].x = i ;  
                M[mcnt ++].y = j ;  
            }  
            else if(s[i][j] == 'H')  
            {  
                H[hcnt].x = i ;  
                H[hcnt ++].y = j ;  
            }  
        }  
    }  
}  
int dis(Node a , Node b)  
{  
    return abs(a.x - b.x) + abs(a.y - b.y) ;  
}  
void buildG()  
{  
    int i , j ;  
    for(i = 0 ; i < mcnt ; i ++)  
    {  
        for(j = 0 ; j < hcnt ; j ++)  
        {  
            w[i][j] = -1 * dis(M[i] , H[j]) ;  
        }  
    }  
}  
int dfs(int u)  
{  
    visx[u] = 1 ;  
    int v ;  
    for(v = 0 ; v < hcnt ; v ++)  
    {  
        if(visy[v]) continue ;  
        int t = Lx[u] + Ly[v] - w[u][v] ;  
        if(t == 0)  
        {  
            visy[v] = 1 ;  
            if(yy[v] == -1 || dfs(yy[v]))  
            {  
                yy[v] = u ;  
                return 1 ;  
            }  
        }  
        else  
        {  
            if(slack[v] > t)  
                slack[v] = t ;  
        }  
    }  
    return 0 ;  
}  
int KM()  
{  
    int i ;  
    int MAX ;  
    for(i = 0 ; i < mcnt ; i ++)  
    {  
        MAX = -1 * INF ;  
        for(int j = 0 ; j < hcnt ; j ++)  
        {  
            if(MAX < w[i][j])  
                MAX = w[i][j] ;  
        }  
        Lx[i] = MAX ;  
    }  
    mem(Ly , 0) ;  
    for(i = 0 ; i < mcnt ; i ++)  
    {  
        for(int j = 0 ; j < hcnt ; j ++)  
        {  
            slack[j] = INF ;  
        }  
        while (1)  
        {  
            mem(visx , 0) ;  // 每次dfs前都要初始化 !!  
            mem(visy , 0) ;  
            if(dfs(i))  
                break ;  
            int d = INF ;  
            int k ;  
            for(k = 0 ; k < hcnt ; k ++)  
            {  
                if(!visy[k] && d > slack[k])  
                {  
                    d = slack[k] ;  
                }  
            }  
            for(k = 0 ; k < hcnt ; k ++)  
            {  
                if(visx[k])  
                {  
                    Lx[k] -= d ;  
                }  
                if(visy[k])  
                {  
                    Ly[k] += d ;  
                }  
                if(!visy[k])  
                {  
                    slack[k] -= d ;  
                }  
            }  
        }  
    }  
    ans = 0 ;  
    for(i = 0 ; i < mcnt ; i ++)  
    {  
        ans += w[ yy[i] ][i] ;  
    }  
}  
void solve()  
{  
    buildG() ;  
    KM() ;  
    printf("%d\n" , ans * (-1)) ;  
}  
int main()  
{  
    while (scanf("%d%d" , &n , &m) != EOF)  
    {  
        if(n == 0 && m == 0)  
            break ;  
        chu() ;  
        init() ;  
        solve() ;  
    }  
    return 0 ;  
}  

 


补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,