XJOI 3876 二进制矩阵

题意

定义二进制矩阵为每个元素都是 \(0\) 或者 \(1\) 的矩阵
现在有一个二进制矩阵,但是有些格子缺失了,用'?'表示
现在知道这个矩阵每行的信息
并且知道矩阵每列的信息,但是不知道具体这些列是对应这个矩阵的哪一列

给每个缺失的格子补上后,求满足条件的字典序最小的二进制矩阵
矩阵的字典序为将每行的字符拼接后的字符串代表的字典序

保证有解

输入格式

第一行输入两个整数 \(n,m\) 表示二进制矩阵的行数和列数 \((1≤n,m≤30)\)
接下来 \(n\) 行每行 \(m\) 个字符,第 \(i\) 行描述矩阵的第 \(i\) 行的信息
接下来 \(m\) 行每行 \(n\) 个字符,第 \(i\) 行描述矩阵某一列的信息

输出格式

输出一个字符矩阵表示字典序最小的矩阵

样例1

2 3
10?
?11
01
10
1?

101
011

样例2

3 1
0
?
1
0?1

0
0
1

样例3

2 2
10
01
10
01

10
01

样例4

4 3
??0
11?
?01
1?1
1???
?111
0?1?

010
110
101
101

分析

把'?'变成 \(0\) 肯定比变成 \(1\) 更优,前面的变成 \(0\) 肯定比后面的变成 \(0\) 更优。
设矩阵 \(A\) 为确定行的矩阵,矩阵 \(B\) 为确定列的信息,但不确定列的位置的矩阵。
我们从上到下,从左到右枚举矩阵 \(A\) 中的每一个'?',先假设其为 \(0\) ,检验是否合法,如果合法,那么就把当前的'?'设为 \(0\) ;如果不合法,就把它设为 \(1\) 。然后继续对下面的'?'执行同样操作。

那么如何验证一个'?'的值是否合法?
我们建立二分图,图左侧为 \(i(i\in [1,m])\) ,图右侧为 \(j(j\in [1,m])\) ,枚举 \(A\) 的每一行和 \(B\) 的每一列的信息,如果某行 \(A_i\) 能和某列 \(B_j\) 匹配,就连边 \((i,j)\) 。最后求出二分图的最大匹配,如果等于完美匹配(即匹配边数等于 \(m\) ),那么就合法;否则不合法。

Code

#include<cstdio>
#include<algorithm>
#include<vector>
#define maxn 103
using namespace std;
int n,m,a[maxn][maxn],b[maxn][maxn];
char t[maxn];
namespace BINGRAPH{
    vector<int> g[maxn];
    int c[maxn];
    bool vis[maxn];
    bool dfs(int u){
        for(int i=0;i<int(g[u].size());i++){
            int v=g[u][i];
            if(vis[v])continue;
            vis[v]=1;
            if(!c[v]||dfs(c[v])){
                c[v]=u;
                return 1;
            }
        }
        return 0;
    }
    int match(){
        int ret=0;
        for(int i=m;i>=1;i--){
            for(int j=1;j<=m;j++)vis[j]=0;
            if(dfs(i))ret++;
        }
        return ret;
    }
    void build(){
        for(int i=1;i<=m;i++){
            g[i].clear();
            c[i]=0;
            for(int j=1;j<=m;j++){
                bool flag=1;
                for(int k=1;k<=n;k++){
                    if(a[k][i]==-1||b[j][k]==-1)continue;
                    if(a[k][i]!=b[j][k]){flag=0;break;}
                }
                if(flag)g[i].push_back(j);
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",t+1);
        for(int j=1;j<=m;j++){
            if(t[j]=='?')a[i][j]=-1;
            else if(t[j]=='1')a[i][j]=1;
            else a[i][j]=0;
        }
    }
    for(int i=1;i<=m;i++){
        scanf("%s",t+1);
        for(int j=1;j<=n;j++){
            if(t[j]=='?')b[i][j]=-1;
            else if(t[j]=='1')b[i][j]=1;
            else b[i][j]=0;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j]==-1){
                a[i][j]=0;
                BINGRAPH::build();
                if(BINGRAPH::match()!=m)a[i][j]=1;
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            putchar(a[i][j]+'0');
        }
        putchar('\n');
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BlogOfchc1234567890/p/9887182.html