• 【KM算法】UVA 11383 Golden Tiger Claw


    题目大意

    给你一个(n×n)的矩阵G,每个位置有一个权,求两个一维数组(row)(col),使(row[i] + col[j]ge G[i][j]),并且(∑row+∑col)最小,输出这个和。

    样例输入

    2
    1 1
    1 1

    数据范围

    (0le Nle 500)

    样例输出

    1 1
    0 0
    2

    思路

    题面花里胡哨,其实就是二分图带权匹配,求的数组其实就是KM算法里的顶标。就是模板啊!这也太水了。

    代码

    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int INF=0x3f3f3f3f;
    const int maxn=500+10;
    int n;
    int g[maxn][maxn];
    int match[maxn],wx[maxn],wy[maxn],slack[maxn];
    bool visx[maxn],visy[maxn];
    
    bool dfs(int u){
        visx[u]=true;
        for(int v=1;v<=n;v++){
            if(!visy[v]){
                int t=wx[u]+wy[v]-g[u][v];
                if(t==0){
                    visy[v]=true;
                    if(match[v]==-1||dfs(match[v])){
                        match[v]=u;
                        return true;
                    }
                }
            else if(slack[v]>t)slack[v]=t;
            }
        }
        return false;
    }
    
    int KM(){
        memset(match,-1,sizeof(match));
        memset(wx,0,sizeof(wx));
        memset(wy,0,sizeof(wy));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(g[i][j]>wx[i])wx[i]=g[i][j];
            }
        }
        for(int x=1;x<=n;x++){
            for(int i=1;i<=n;i++)
                slack[i]=INF;
            while(1){
                memset(visx,false,sizeof(visx));
                memset(visy,false,sizeof(visy));
                if(dfs(x))break;
                int minz=INF;
                for(int i=1;i<=n;i++)
                   if(!visy[i]&&minz>slack[i])
                        minz=slack[i];
                for(int i=1;i<=n;i++)
                   if(visx[i])wx[i]-=minz;
                for(int i=1;i<=n;i++){
                    if(visy[i])wy[i]+=minz;
                    else slack[i]-=minz;
                }
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
           ans+=wx[i]+wy[i];
        return ans;
    }
    
    int main(){
        while(~scanf("%d",&n)){
            memset(g,0,sizeof(g));
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    scanf("%d",&g[i][j]);
                }
            }
    
            int ans=KM();
            printf("%d",wx[1]);
            for(int i=2;i<=n;i++)
                printf(" %d",wx[i]);
    
            printf("
    ");
    
            printf("%d",wy[1]);
            for(int i=2;i<=n;i++)
                printf(" %d",wy[i]);
    
            printf("
    ");
    
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    带权并查集
    Dungeon Master (luo 三维 BFS )
    迷宫问题 (最短路径保存输出)
    Aggressive cows (北京大学ACM-ICPC竞赛训练暑期课 )
    滑雪 (北京大学ACM-ICPC竞赛训练暑期课 )
    棋盘问题 (北京大学ACM-ICPC竞赛训练暑期课 )
    简单的整数划分问题 ( 北京大学ACM-ICPC竞赛训练暑期课 )
    马走日 (DFS)
    蓝桥杯 (计算路径)
    最长单词 (分割字符串)(蓝桥杯-算法提高)
  • 原文地址:https://www.cnblogs.com/Midoria7/p/12860197.html
Copyright © 2020-2023  润新知