工作人员集合M和工作N是二分图的两个部分,工作人员i对工作j的满意度k作为边
<
i,j
>
的权值,要求一个令所有工作人员
满意度最大的匹配就是求这个二分图的带权最大匹配。这里用到KM算法,由于不是很懂KM算法,所以要感谢
http:
//
www.cnblogs.com/north_dragon/archive/2010/06/03/1750789.html
这位大牛的模板。在一年中最较特殊的2月的最后一天抓住AC的机会。
#include
<
iostream
>
#include
<
cstring
>
#include
<
cstdio
>
using
namespace
std;
const
int
maxData
=
1000000000
;
const
int
arraysize
=
110
;
int
w[arraysize][arraysize];
//
权值
int
match[arraysize];
//
保存匹配信息,其中i为Y中的顶点标号,match[i]为X中顶点标号
int
lx[arraysize],ly[arraysize],slack[arraysize];
//
lx[]为左顶点的顶标,ly[]为有顶点的顶标,slack[]记录右顶点的松弛量
bool
finalx[arraysize],finaly[arraysize];
//
标记在一次DFS中,Xi与Yi是否在交错树上
int
ncount;
bool
DFS(
int
p)
{
int
i,j,t;
finalx[p]
=
true
;
//
将左顶点标记为真
for
(i
=
1
;i
<=
ncount;
++
i)
{
if
(finaly[i])
continue
;
int
temp
=
lx[p]
+
ly[i]
-
w[p][i];
if
(temp
==
0
)
{
finaly[i]
=
true
;
t
=
match[i];
match[i]
=
p;
if
(t
==
0
||
DFS(t))
return
true
;
match[i]
=
t;
}
else
if
(slack[i]
>
temp)
//
检查边(i,j)时,如果它不在相等子图中,则让slack[i]变成原值与A[p]+B[i]-w[p,i]的较小值
{
slack[i]
=
temp;
}
}
return
false
;
}
int
KM()
{
int
i,j;
memset(ly,
0
,
sizeof
(ly));
//
将右结点的可行顶标的值设置为0
memset(match,
0
,
sizeof
(match));
for
(i
=
1
;i
<=
ncount;
++
i)
{
lx[i]
=-
maxData;
for
(j
=
1
;j
<=
ncount;
++
j)
{
if
(lx[i]
<
w[i][j])
//
将左顶点的可行顶标的值设置为所有与左顶点关联的边的最大权
lx[i]
=
w[i][j];
}
}
//
从左顶点依次寻找增广路径
for
(i
=
1
;i
<=
ncount;
++
i)
{
for
(j
=
1
;j
<=
ncount;
++
j) slack[j]
=
maxData;
//
每次寻找增广路径将松弛量函数初始化无穷大
while
(
1
)
{
memset(finalx,
0
,
sizeof
(finalx));
memset(finaly,
0
,
sizeof
(finaly));
if
(DFS(i))
break
;
int
d
=
maxData;
for
(j
=
1
;j
<=
ncount;
++
j)
//
d应该等于:Min{A[i]+B[j]-w[i,j] | Xi在交错树中,Yi不在交错树中}。
{
if
(
!
finaly[j]
&&
d
>
slack[j])
d
=
slack[j];
}
//
若未找到完备匹配则修改可行顶标的值
for
(j
=
1
;j
<=
ncount;
++
j)
{
if
(finalx[j]) lx[j]
-=
d;
if
(finaly[j]) ly[j]
+=
d;
else
slack[j]
-=
d;
}
}
}
int
ans
=
0
;
//
ans为权值和
for
(i
=
1
;i
<=
ncount;
++
i)
{
ans
-=
(lx[i]
+
ly[i]);
}
return
ans;
}
int
main()
{
int
i,j;
while
(scanf(
"
%d
"
,
&
ncount)
&&
ncount)
{
memset(w,
0
,
sizeof
(w));
for
(i
=
1
;i
<=
ncount;
++
i)
{
for
(j
=
1
;j
<=
ncount;
++
j)
{
scanf(
"
%d
"
,
&
w[i][j]);
//
w[j][i] = w[i][j];
}
}
printf(
"
%d\n
"
,
-
KM());
}
return
0
;
}