UVA 11383 Golden Tiger Claw(KM算法)

来源:互联网 发布:天猫魔盒淘宝不卖了吗 编辑:程序博客网 时间:2024/06/05 04:04

题目:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2378

题目大意:给你一个 n*n 的矩阵,要求你对每行和每列设一个值 row(i)和col(i),设的对于任意格子w( i , j ) ,满足 w( i , j ) <= row( i ) + col( j ) ,并且所有的 row( i ) 和 col( i )的和最小。

解题思路:这个在二分图匹配中粗现,但是实在看不出有什么可以和二分图联系上的,后来看了书才发现,原来这道题是 KM 算法的一个副产品。在 KM 里顶标 Lx 和 Ly,Lx( x ) + Ly( y ) >= w( x , y ) ,然后就根据这个不等式,直接上 KM 就行。算法结束后,所有的顶标和是最小的。(这句话需要好好理解!)

        很好的一道开拓性思维的题目啊!~~~~

代码如下:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int INF = 0x0fffffff;const int MAXN = 555;int n;int w[MAXN][MAXN];int lx[MAXN],ly[MAXN],slack[MAXN];int s[MAXN],t[MAXN],left[MAXN];int match(int i){    s[i] = 1;    for(int j = 1;j <= n;j++)        if(!t[j])        {            int tmp = lx[i]+ly[j]-w[i][j];            if(tmp == 0)            {                t[j] = 1;                if(!left[j] || match(left[j]))                {                    left[j] = i;                    return 1;                }            }            else slack[j] = min(slack[j],tmp);        }    return 0;}void update(){    int a = INF;    for(int i = 1;i <= n;i++)        if(!t[i]) a = min(a,slack[i]);    for(int i = 1;i <= n;i++)    {        if(s[i]) lx[i] -= a;        if(t[i]) ly[i] += a;    }}void km(){    for(int i = 1;i <= n;i++)    {        left[i] = lx[i] = ly[i] = 0;        for(int j = 1;j <= n;j++)            lx[i] = max(lx[i],w[i][j]);    }    for(int i = 1;i <= n;i++)    {        for(int j = 1;j <= n;j++)            slack[j] = INF;        while(1)        {            for(int j = 1;j <= n;j++) s[j] = t[j] = 0;            if(match(i))                break;            else update();        }    }}int main(){    while(~scanf("%d",&n))    {        for(int i = 1;i <= n;i++)            for(int j = 1;j <= n;j++)                scanf("%d",&w[i][j]);        km();        int sum = lx[1];        printf("%d",lx[1]);        for(int i = 2;i <= n;i++)        {            sum += lx[i];            printf(" %d",lx[i]);        }        puts("");        sum += ly[1];        printf("%d",ly[1]);        for(int i = 2;i <= n;i++)        {            sum += ly[i];            printf(" %d",ly[i]);        }        puts("");        printf("%d\n",sum);    }    return 0;}


0 0
原创粉丝点击