1. 程式人生 > >POJ 2195 二分圖帶權完美匹配

POJ 2195 二分圖帶權完美匹配

Description:

給出一個矩陣,矩陣中m代表人,H代表房子,房子和人的數量相等,人每次可上下左右移動一格,人的移動互不干擾,問所有的人都進入互不相同不同的房子,所有人最少一共走多少步。

Input:

多組資料

每組第一行是n和m,分別代表矩陣的行數和列數。

之後是個n*m的矩陣。

Output:

每組資料輸出一個整數代表最少總步數。

Analysis:

因為人的行動只要不出界是不受到任何限制的,所以只要確定了人與房子的匹配,每個人必然都是以最短路線走入各自房子才能保證步數最小。也即某個人到某個房子所要走的步數對答案的貢獻是確定的(|r1-r2|+|c1-c2|),所以問題變為求人與房子的一個完美匹配,使得權和最小。可用KM演算法。

更具體來說,KM演算法求的是最大權和,所以可以直接把原有的權值取為負值,在最後把答案取反還原。這裡相當於把KM演算法當做一個黑箱,把輸入輸出都做一個取反變換從而達到求最小權和的目的。

程式碼:

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
int readint() { int x; cin >> x; return x; }
const int INF = 1 << 30;
const int maxn = 5005;
vector<pair<int,int> > px,py;
int n,m;
int w[maxn][maxn],mint;
int vall[maxn],valr[maxn],visl[maxn],visr[maxn],linkl[maxn],linkr[maxn];

bool find(int u){
    visl[u]=1;
    for(int i=0;i<py.size();++i){
        if(!visr[i]){
            int t=vall[u]+valr[i]-w[u][i];
            if(t==0){
                visr[i]=1;
                if(linkr[i]==-1||find(linkr[i])){
                    linkl[u]=i;linkr[i]=u;
                    return true;
                }
            }
            else mint=min(mint,t);
        }
    }
    return false;
}

int KM(){
    memset(linkl,-1,sizeof(linkl));
    memset(linkr,-1,sizeof(linkr));
    for(int i=0;i<px.size();++i){
        while(1){
            memset(visl,0,sizeof(visl));
            memset(visr,0,sizeof(visr));
            mint=INF;
            if(find(i))break;

            for(int j=0;j<px.size();++j)
                if(visl[j])vall[j]-= mint;
            for(int j=0;j<py.size();++j)
                if(visr[j])valr[j]+= mint;
        }
    }

    int ans=0;
    for(int i=0;i<px.size();++i){
        ans+=w[i][linkl[i]];
    }
    return ans;
}

int main()
{

	//freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
	//freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);

    while(~scanf("%d%d",&n,&m)){
            if(n==0&&m==0)break;
        string s;px.clear(),py.clear();
        for(int i=0;i<n;++i){
            cin>>s;
            for(int j=0;j<m;++j){
                if(s[j]=='m'){
                    px.push_back({i,j});
                }
                else if(s[j]=='H'){
                    py.push_back({i,j});
                }
            }
        }

        memset(vall,0,sizeof(vall));
        memset(valr,0,sizeof(valr));

        for(int i=0;i<px.size();++i)
        for(int j=0;j<py.size();++j){
            w[i][j]=-(abs(px[i].first-py[j].first)+abs(px[i].second-py[j].second));
            vall[i]=max(vall[i],w[i][j]);
        }

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

    }

	return 0;
}