• Superdoku 二分图匹配


    题目链接:https://cn.vjudge.net/problem/Kattis-superdoku

    题目大意:给你一个n*n的矩阵,给你这个矩阵的前k行,问你是否能构成矩阵使得每一行每一列都是1~n的排列。(即不考虑对角线的数独)

    题目分析:一个标准的二分图匹配问题,会用到匈牙利算法

    匈牙利算法的趣味介绍:https://blog.csdn.net/dark_scope/article/details/8880547

    在看这个题,既然题目已经帮我们把前k行确定了(如果题目给出的k是1,那么我们就自己设置一个第一行),我们直接从第k+1行开始进行处理,在这里我引用刚才那个趣味介绍里的说法来分析,我们可以把每一列看做是一个男生,1-n个数看做是一个女生,如果一列中之前没有出现数字i,我们可以理解为该行(男生)和数字i(女生)互有好感(显然该列存在数字i就等同没好感了)。

    这里在进行匹配时,是以行为单位,从左到右一个个匹配的,和其进行匹配的,是该数字所在列。

    net数组相当于girl数组,是数字i匹配对象所在的行数,ans数组是映射数组,帮助我们进行数据的修改。

    具体可以看代码了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    const int maxn=2e5+7;
    const ll inf=1e18+7;
    const double pi=acos(-1);
    int n,k;
    int h[110][110],l[110][110],a[110][110],vis[110],net[110],ans[110];
    bool find(int pos){
        for(int i=1;i<=n;i++){
            if(l[pos][i]||vis[i])continue;
            vis[i]=1;
            if(!net[i]||find(net[i])){
                net[i]=pos;
                ans[pos]=i;
                return true;
            }
        }
        return false;
    }
    
    bool match(int pos){
        memset(net,0,sizeof(net));
        int num=0;
        for(int i=1;i<=n;i++){
            memset(vis,0,sizeof(vis));
            if(find(i)){
                num++;
            //    a[pos][i]=ans[i];
            //    h[pos][ans[i]]=1;
            //    l[i][ans[i]]=1;
            }
        }
        return num==n;//如果每一列都成功匹配,则返回true 
    }
    
    bool solve(){
        int num=0;
        for(int i=k+1;i<=n;i++){
            if(match(i)){
                num++;
            }
            for(int j=1;j<=n;j++){
                a[i][j]=ans[j];
                h[i][ans[j]]=1;
                l[j][ans[j]]=1;
            }
        }
        return num==n-k;//k+1之后的行全部成功匹配则返回true 
    }
    int main(){
        scanf("%d%d",&n,&k);
        memset(h,0,sizeof(h));//二维数组初始化也可以直接用memset,不过fill需要做修改 
        memset(l,0,sizeof(l));
        int flag=0; 
        for(int i=1;i<=k;i++){
            for(int j=1;j<=n;j++){
                scanf("%d",&a[i][j]);
                if(++h[i][a[i][j]]>1)flag=1;
                if(++l[j][a[i][j]]>1)flag=1;
            }
        }
        if(flag) {
            printf("no
    ");
            return 0;
        }
        if(k==0){//这种情况下我们要自己设一个k 
            for(int i=1;i<=n;i++){
                a[1][i]=i;
                h[1][i]=1;
                l[i][i]=1;
            }
            k=1;//记得将k改为1 
        }
        if(!solve()) printf("no
    ");
        else{
            printf("yes
    ");
            for(int i=1;i<=n;i++){
                for(int j=1;j<n;j++)
                printf("%d ",a[i][j]);
                printf("%d
    ",a[i][n]);
            }
        }
        return 0;
    }
  • 相关阅读:
    DP动态规划【专辑@AbandonZHANG】
    Abandon の DP动态规划【专辑】(长期更新)
    可持久化线段树【专题@AbandonZHANG】
    DP动态规划【专辑@AbandonZHANG】
    最近公共祖先LCA 【专题@AbandonZHANG】
    最近公共祖先LCA 【专题@AbandonZHANG】
    可持久化线段树【专题@AbandonZHANG】
    SDK , MFC 和 API
    2007年12月英语四级预测作文大全3
    Ajax介绍
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11262256.html
Copyright © 2020-2023  润新知