标签:blog class code int strong 2014
本来是打算昨天晚上写的, 昨天网速渣的连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);
}
}
POJ 2195 二分图最小权匹配KM算法,布布扣,bubuko.com
标签:blog class code int strong 2014
原文地址:http://blog.csdn.net/u012896700/article/details/25202261