$$ \newcommand{\seq}[2]{{#1}_{1},{#1}_{2},\cdots,{#1}_{#2}} \newcommand{\num}[1]{1,2,\cdots,#1} \newcommand{\stra}[2]{\begin{bmatrix}#1 \\ #2\end{bmatrix}} \newcommand{\strb}[2]{\begin{Bmatrix}#1 \\ #2\end{Bmatrix}} \newcommand{\dw}[1]{\underline{#1}} \newcommand{\up}[1]{\overline{#1}} $$

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;
}
posted @ 2018-11-01 08:02  chc_1234567890  阅读(415)  评论(0编辑  收藏  举报