UVA11383 Golden Tiger Claw

传送门:

https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2378

翻译

在一个N*N的方格中,各有一个整数w(i,j),现在要求给每行构造row(i),给每列构造col(j),使得任意w(i,j)<=row(i)+col(j),输出row(i)与col(j)之和最小的方案。

没什么好说的。。。

上来一看题觉得挺唬人,不过仔细一看这个玩意跟我们跑带权二分图KM算法时的要求一模一样。row和col不就是我们X部和Y部的lx跟ly吗?正好我们KM算法求的ans本身就是最优匹配的最小值,跟这道题给的一模一样。所以虽然这道题跟二分图没什么关系,但直接套一个KM的板子即为正解。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
#define maxn 510
#define maxm 250010
#define INF 0x3f3f3f3f
struct node{
    int to,val,next;
}e[maxm];int len;
int head[maxn];
void Add(int x,int y,int c){
    e[++len].to=y;
    e[len].val=c;
    e[len].next=head[x];
    head[x]=len;
}
int a[maxn][maxn];
int n;
int lx[maxn],ly[maxn],match[maxn],slack[maxn];
bool visx[maxn],visy[maxn];
bool Find(int x){
    visx[x]=1;
    for(int i=head[x];i;i=e[i].next) 
        if(!visy[e[i].to]){
            int y=e[i].to;
            if(e[i].val==lx[x]+ly[y]){
                visy[y]=1;
                if(!match[y]||Find(match[y])){  
                    match[y]=x;
                    return 1;
                }
            }
            else slack[y]=min(slack[y],lx[x]+ly[y]-e[i].val);
        }
    return 0;
}

void KM(){
    memset(match,0,sizeof(match));
    memset(lx,0,sizeof(lx));
    memset(ly,0,sizeof(ly));
    for(int i=1;i<=n;i++)
    for(int j=head[i];j;j=e[j].next) 
        lx[i]=max(lx[i],e[j].val);
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)
            slack[j]=INF;
        while(1){
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(Find(i)) break;
            int delta=INF;
            for(int j=1;j<=n;j++){
                if(!visy[j]){
                    delta=min(delta,slack[j]);
                }
            }
            if(delta==INF) return;
            for(int j=1;j<=n;j++)
            {
                if(visx[j]) lx[j]-=delta;
                if(visy[j]) ly[j]+=delta;
                else slack[j]-=delta;
            }
        }
    }
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        len=0;
        memset(head,0,sizeof head);
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++){
              int x;
              scanf("%d",&x);
              Add(i,j,x);
          }
        KM();
        for(int i=1;i<=n;i++) printf("%d ",lx[i]);
        printf("\n");
        for(int i=1;i<=n;i++) printf("%d ",ly[i]);
        printf("\n");
        int ans=0;
        for(int i=1;i<=n;i++) ans+=lx[i]+ly[i];
        printf("%d\n",ans);
    }
    return 0;
}

posted @ 2020-05-11 17:32  zfio  阅读(103)  评论(0编辑  收藏  举报