• 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("
    ");
            for(int i=1;i<=n;i++) printf("%d ",ly[i]);
            printf("
    ");
            int ans=0;
            for(int i=1;i<=n;i++) ans+=lx[i]+ly[i];
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    第3、4、5讲
    .NetCore使用EF5操作Oracle,解决列自增序列绑定不生效的问题
    ASP.NET Core 之 Identity 入门(一)
    ORACLE NLS_DATE_FORMAT设置
    ORA12514遇到了怎么排查问题出在哪
    Oracle特殊字符查询语句
    ORA00821: Specified value of sga_target 3072M is too small, needs to be at least 12896M
    如何定位哪些SQL产生了大量的Redo日志
    Oracle定位对阻塞的对象或锁信息
    Oracle Undo和Redo的关系,区别及相关查询
  • 原文地址:https://www.cnblogs.com/Zfio/p/12870487.html
Copyright © 2020-2023  润新知