sicily 1303 Job Assigment(二分图最大权匹配)

View Code
   
     
工作人员集合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 ;
}

你可能感兴趣的:(job)