您的位置:首页 > 其它

poj2195最小权值二分匹配KM算法

2015-11-05 21:43 218 查看

poj2195KM算法

== 我只是自己看看的 ==

具体要看km是怎么弄的请看此链接:

这是我觉得网络上将的最让我懂的

/content/2633357.html

然后普通的KM是n4,这题要用n3的才能过,n4我超时

这题只要构图正确,弄出二维矩阵,直接扔到模板上就出结果了

代码部分

我给下输入的构图代码

char s[MAXN];
int i, j, res;
while (scanf("%d%d", &n, &m) && (n + m))
{
H = M = res = 0;
for (i = 0; i < n; i++)
{
scanf("%s", s);
for (j = 0; j < m; j++)
{
if (s[j] == 'H')
house[H].r = i, house[H++].c = j;
else if (s[j] == 'm')
man[M].r = i, man[M++].c = j;
}
}
for (i = 0; i < M; i++) //求最小带权匹配可以将权值改为负数
{
for (j = 0; j < H; j++)
{
map[i][j] = abs(man[i].r - house[j].r) + abs(man[i].c - house[j].c);
}
}


KM的代码

/*
*  KM算法,求最大或最小权二分匹配,用二维矩阵完成
*/

int map[MAXN][MAXN];//二维矩阵权值
int A[MAXN];//A的标记值
int B[MAXN];//B的标记值
bool visA[MAXN];
bool visB[MAXN];
int match[MAXN];//匹配的点
int slack[MAXN];

bool find_path(int i)//找路径
{
visA[i] = true;
for (int j = 0; j < H; j++)
{
if (!visB[j] && A[i] + B[j] == map[i][j])
{
visB[j] = true;
if (match[j] == -1 || find_path(match[j]))
{
match[j] = i;
return true;
}
}
else if (A[i] + B[j] > map[i][j]) //j属于B,且不在交错路径中
slack[j] = min(slack[j], A[i] + B[j] - map[i][j]);
}
return false;
}
void KM(int num)//true求最大权,false求最小权,num要匹配的对数
{
int i, j, d;
memset(A, 0, sizeof(A));
memset(B, 0, sizeof(B));
memset(match, -1, sizeof(match));
for (i = 0; i < num; i++)
{
for (j = 0; j < num; j++)
{
A[i] = max(map[i][j], A[i]);
}
}
for (i = 0; i < num; i++)
{
for (j = 0; j < num; j++)
slack[j] = inf;
while (1)
{
memset(visA, 0, sizeof(visA));
memset(visB, 0, sizeof(visB));
if (find_path(i))
break; //返回true退出,从i点出发找到交错路径则跳出循环
for (d = inf, j = 0; j < num; j++) //取最小的slack[j]
{
if (!visB[j] && d > slack[j])
d = slack[j];
}
for (j = 0; j < num; j++) //集合A中位于交错路径上的-d
{
if (visA[j]) A[j] -= d;
}
for (j = 0; j < num; j++) //集合B中位于交错路径上的+d
{
if (visB[j])
B[j] += d;
else
slack[j] -= d; //注意修改不在交错路径上的slack[j]
}
}
}
}
int Kuhn_Munkras(bool maxweight, int num)
{
if (!maxweight)
{ //如果求最小匹配,则要将边权取反
for (int i = 0; i < num; i++)
{
for (int j = 0; j < num; j++)
{
map[i][j] = -map[i][j];
}
}
}
KM(num);
int sum = 0;
for (int i = 0; i < num; i++)
{
if (match[i] >= 0)
{
sum += map[match[i]][i];
}
}
if (!maxweight)
sum = -sum;
return sum;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: