Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=3722
【前言】
又搜刮来了一份代码。
用于求二分图的带权匹配。
记得以前看到过这道题,不够没什么思路。
昨天也是。
于是今天学了KM算法。
虽然还处于不求甚解的地步,但有终归胜于无。
【思路】
KM算法是基于匈牙利算法的。
具体参考tianyi的讲解。
对于KU算法,除了求权和最大,还可以求权和最小以及求权积最大。
对于求权和最小,只需要将每个权值取相反数,再求最大权和,结果再取相反数即可。
对于求权积最大,则需要把每个权值转化为对数,从而进行求最大权和的运算,最后再求回指数即可。
【代码】
代码参考:http://baike.baidu.com/view/739278.htm
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=200;
const int INF=2147483647;
int w[maxn+5][maxn+5];
int lx[maxn+5],ly[maxn+5];
int linky[maxn+5];
int visx[maxn+5],visy[maxn+5];
int lack;
char str[maxn+5][1005];
bool find(int x, int n)
{
visx[x] = true;
for(int y=0; y<n; y++)
{
if(visy[y])continue;
int t = lx[x]+ly[y]-w[x][y];
if(t==0)
{
visy[y] = true;
if(linky[y]==-1 || find(linky[y], n))
{
linky[y] = x;
return true;
}
}
else if(lack>t) lack = t;
}
return false;
}
void KM(int n)
{
int i, j, x;
for (i=0; i<n; i++)
linky[i] = -1;
for (i=0; i<n; i++)
{
for(j=0; j<n; j++)
{
if(w[i][j]>lx[i])
lx[i] = w[i][j];
}
}
for(x=0; x<n; x++)
{
while(1)
{
for (i=0; i<n; i++)
visx[i] = visy[i] = 0;
lack=INF;
if(find(x, n)) break;
for(i=0; i<n; i++)
{
if(visx[i]) lx[i] -= lack;
if(visy[i]) ly[i] += lack;
}
}
}
}
int main()
{
int n;
int i, j, k, l;
while(scanf("%d", &n)!=EOF)
{
for (i=0; i<n; i++)
scanf("%s", str[i]);
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
{
if (i==j)
w[i][j] = 0;
else
{
for (k=0, l=strlen(str[i])-1; str[j][k]==str[i][l] && str[j][k]!='\0' && l>=0; k++,l--);
w[i][j] = k;
}
}
}
KM(n);
int sum = 0;
for (i=0; i<n; i++)
sum += w[linky[i]][i];
printf("%d\n", sum);
}
return 0;
}