【CQOI2014】和谐矩阵
Time Limits: 1s Memory Limits: 512MB Special Judge
Description
我们称一个由0和1组成的矩阵是和谐的,当且仅当每个元素都有偶数个相邻的1.一个元素相邻的元素包括它本身,及他上下左右的4个元素(如果存在)。
给定矩阵的行数和列数,请计算并输出一个和谐的矩阵。注意:所有元素为0的矩阵是不允许的。
Input
输入一行,包含两个空格分隔的整数m和n,分别表示矩阵的行数和列数。
Output
输出包含m行,每行n个空格分隔整数(0或1),为所求矩阵。测试数据保证有解。
Sample Input
4 4
Sample Output
0 1 0 0
1 1 1 0
0 0 0 1
1 1 0 1
Data Constraint
1<=m,n<=40
题目大意:
求一个非全0的n*m的01矩阵,使得每个位置满足:与其相邻或本身的’1’的个数为偶数
解题思路
emm。。。难道是构造?好吧感觉不太可能。
算法1
先说说一个很朴素的思路:
发现了这个没?——
0 1 0 0 0 1 0 0 0 1 0
1 1 1 0 1 1 1 0 1 1 1
0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 1 1 1 0 1 1 1
0 1 0 0 0 1 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 1 0 0 0 1 0
1 1 1 0 1 1 1 0 1 1 1
这个方阵是成立的,找找规律——方阵由小方阵组成,方阵中间有0间隔,且相邻的方阵对称。上矩阵中,小方阵为:
0 1 0
1 1 1
观察一下,发现小方阵的内部也是成立的
同时,由于相邻的方阵对称,方阵之间的0只有左右或上下2个1,中间的依然成立
故整个方阵成立
于是——是否可以枚举使用多小的方阵,通过翻转求大方阵呢?
反正我没这么实践。
算法2
我想,假设一开始全都为0
每个点及周围的奇偶性(简单写了,意义如题)为0(偶,1为奇),假设选择某个点,只能影响到自身及周围的奇偶性,恰好是取反。
对于一个符合要求的矩阵,每个点的奇偶性为0,也就是说,对于每个点所带来的影响,等同于这个矩阵选其他点带来的影响。
for example
一个符合要求的矩阵:1 1 0 1 1
由1 1 0 1 0
和0 0 0 0 1
组成;
1 1 0 1 0
的影响为0 0 0 1 1
,0 0 0 0 1
的影响为0 0 0 1 1
等同于1 1 0 1 0
的影响;
根据这个思路,我们设
f(i,j)
表示选(i,j)带来的影响,那么一个满足要求的图选的点集为D,有
Xor(i,j)∈Df(i,j)=∅
,同时
f(i,j)=Xor(x,y)∈D,(x,y)≠(i,j)f(x,y)
,这个利用线性基可以实现。每次塞入
f(i,j)
,返回的是能否由线性基的某些状态构成,记录下能由哪些状态构成即可,bitset维护。
虽然理论上是
O((nm)3ω)
但线性基不可能每一位都异或,实际上nm=5000也能过
#include<cstring>
#include<cstdio>
#include<bitset>
#define N 22501
#define bt bitset<N>
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define f(a,b) ((a-1)*m+b-1)
using namespace std;
int n,m,T;
struct B{
bt sta,mem;
void clear(){
sta.reset();mem.reset();
}
}tmp;
struct Base{
B l[N];
B ins(B a){
fd(i,T,0)if(a.sta[i]){
if(l[i].sta.none()){
l[i]=a;break;
}a.sta^=l[i].sta;a.mem^=l[i].mem;
}return a;
}
void init(){
fd(i,T,0)l[i].clear();
}
}graph;
int main(){
scanf("%d %d",&n,&m);T=n*m-1;graph.init();
fo(i,1,n)fo(j,1,m){
tmp.clear();
tmp.mem.set(f(i,j));
tmp.sta.set(f(i,j));
if(i>1)tmp.sta.set(f(i-1,j));
if(j>1)tmp.sta.set(f(i,j-1));
if(i<n)tmp.sta.set(f(i+1,j));
if(j<m)tmp.sta.set(f(i,j+1));
tmp=graph.ins(tmp);
if(tmp.sta.none()){
fo(I,1,n){
fo(J,1,m)if(tmp.mem[f(I,J)])printf("1 ");else printf("0 ");printf("\n");
}
fclose(stdin);fclose(stdout);
return 0;
}
}printf("-1");
}