zoukankan      html  css  js  c++  java
  • 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(iin [1,m])) ,图右侧为 (j(jin [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('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    P2764 最小路径覆盖问题
    P1402 酒店之王 网络流
    P2597 [ZJOI2012]灾难 拓扑排序
    FJOI2017 矩阵填数
    2019.2.27模拟
    2019.2.26模拟
    SDOI2013 方程
    [AH2017/HNOI2017]抛硬币
    Lucas定理和扩展Lucas定理
    LuoguP4861 按钮
  • 原文地址:https://www.cnblogs.com/BlogOfchc1234567890/p/9887182.html
Copyright © 2011-2022 走看看