1. 程式人生 > >POJ 2195 二分圖最小權匹配KM演算法

POJ 2195 二分圖最小權匹配KM演算法

本來是打算昨天晚上寫的, 昨天網速渣的連CSDN都進不去,沒辦法 只能現在來寫了

先寫寫對KM演算法的理解,KM演算法是對每個點設定一個頂標,只有當邊長等於兩邊點的頂標之和的時候才進行增廣,這樣就能保證得到的一定是最大權匹配。

如果找不到匹配的時候就對交替路中X集合的頂標減少一個d Y集合的頂標增加一個d。

這樣兩個點都在交替路中的時候x[i]+y[i]的和不邊

X在 Y不在的時候x[i]+y[i]減少,可能就會為圖增加一對匹配。

X不在Y在的時候x[i]+y[i]增加, 原來不在現在依然不在其中。

題意:有n個人n個房子,每人進一個房子,求最少的總距離。

思路:對每條邊取相反數,然後得到的結果再取相反數,就能得到最小權匹配。

#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#include<math.h>
#include<iostream>
#define INF 10000000
using namespace std;
char map[105][105];
struct point{
   int x,y;
}X[105],Y[105];
int W[105][105];
int macy[105];
bool check[105];
bool checkx[105];
int zx[105];
int zy[105];
int Y1[105];
int n;
bool dfs(int u)
{
    checkx[u]=1;
    for(int i=0;i<n;i++)
    {
        if(zx[u]+zy[i]==W[u][i]&&!check[i])
        {
            check[i]=1;
            if(macy[i]==-1||dfs(macy[i]))
            {
                macy[i]=u;
                return 1;
            }
        }
        if(!check[i])
        {
            Y1[i]=min(Y1[i],zx[u]+zy[i]-W[u][i]);
        }
    }
    return 0;
}
void gx()
{
    int a=INF;
    for(int i=0;i<n;i++)
        if(!check[i])
        a=min(a,Y1[i]);
    for(int i=0;i<n;i++)
    {
        if(check[i]) zy[i]+=a;
        if(checkx[i]) zx[i]-=a;
    }
}
void xyl()
{
    memset(macy,-1,sizeof(macy));
    for(int i=0;i<n;i++)
    {
        memset(check,0,sizeof(check));
        memset(checkx,0,sizeof(checkx));
        if(!dfs(i))
        {
            i--;
            gx();
        }
    }
}
int main()
{
    int N,M;
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        if(N==0&&M==0) return 0;
        for(int i=0;i<N;i++)
            scanf("%s",map[i]);
            int r1=0,r2=0;
        for(int i=0;i<N;i++)
            for(int j=0;j<M;j++)
        {
            if(map[i][j]=='H')
            {
                X[r1].x=i;
                X[r1].y=j;
                r1++;
            }
            else if(map[i][j]=='m')
            {
                Y[r2].x=i;
                Y[r2].y=j;
                r2++;
            }
        }
        memset(zy,0,sizeof(zy));
        for(int i=0;i<r1;i++)
       {
           zx[i]=-INF;
           for(int j=0;j<r2;j++)
            {
                W[i][j]=abs(X[i].x-Y[j].x)+abs(X[i].y-Y[j].y);
                W[i][j]*=-1;
                zx[i]=max(zx[i],W[i][j]);
                Y1[j]=INF;
            }
       }
        n=r1;
        //return 0;
        xyl();
        int p=0;
        for(int i=0;i<n;i++)
        {
            int u=macy[i];
            p+=W[u][i];
        }
        printf("%d\n",-p);
    }
}