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\n");
        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\n");
    else{
        printf("yes\n");
        for(int i=1;i<=n;i++){
            for(int j=1;j<n;j++)
            printf("%d ",a[i][j]);
            printf("%d\n",a[i][n]);
        }
    }
    return 0;
}

 

上一篇:luogu1091:合唱队形


下一篇:【Volta】自动化测试-python基础1-基本数据类型