题目:
给定一个
n
×
m
n \times m
n×m的01矩阵,现有一种操作:选择一个
2
×
2
2 \times 2
2×2的子矩阵,选择其中三个不同位置的元素,将它们翻转(0变成1,1变成0)。使用这种操作,将01矩阵的元素全变成0。让你构造操作序列,使操作总数小于等于
n
m
nm
nm。
(
2
≤
n
,
m
≤
100
)
(2 \le n,m \le 100)
(2≤n,m≤100)
题解:
首先可以将每个状态的
2
×
2
2 \times 2
2×2的矩阵清零的最短长度的操作序列进行预处理,一共也就
2
4
2^4
24种状态,建个转移图,反向建边,从全0的状态出发
b
f
s
bfs
bfs跑最短路即可。
接下来考虑构造,我们两行两行地来看,对于
i
i
i行和
i
+
1
i+1
i+1行,我们将
j
j
j列(
j
≤
m
−
2
j \le m-2
j≤m−2)和
j
+
1
j+1
j+1列的四个元素组成
2
×
2
2 \times 2
2×2的矩阵,进行操作将
j
j
j列的两个元素变成0,对于最后两列组成的
2
×
2
2 \times 2
2×2矩阵,直接用之前预处理好的对应状态的操作序列即可。如果
n
n
n为奇数,那么最后一行就多出来了,那么我们将
n
−
1
n-1
n−1行和
n
n
n行再进行一次上述操作。
来看一下这种操作方式的次数,上界为
l i m = ⌈ n 2 ⌉ ( m − 2 ) + 4 ⌊ n 2 ⌋ + 3 lim=\lceil \tfrac{n}{2} \rceil(m-2)+4 \lfloor \tfrac{n}{2} \rfloor +3 lim=⌈2n⌉(m−2)+4⌊2n⌋+3
≤ ⌈ n 2 ⌉ ( m − 2 ) + 4 ⌈ n 2 ⌉ − 1 \le \lceil \tfrac{n}{2} \rceil(m-2)+4 \lceil \tfrac{n}{2} \rceil -1 ≤⌈2n⌉(m−2)+4⌈2n⌉−1
= ⌈ n 2 ⌉ ( m + 2 ) − 1 =\lceil \tfrac{n}{2} \rceil(m+2)-1 =⌈2n⌉(m+2)−1
= ⌈ n 2 ⌉ m + 2 ⌈ n 2 ⌉ − 1 = \lceil \tfrac{n}{2} \rceil m+2\lceil \tfrac{n}{2} \rceil -1 =⌈2n⌉m+2⌈2n⌉−1
≤ ⌈ n 2 ⌉ m + n + 1 − 1 \le \lceil \tfrac{n}{2} \rceil m+n+1 -1 ≤⌈2n⌉m+n+1−1
= ⌈ n 2 ⌉ m + n =\lceil \tfrac{n}{2} \rceil m+n =⌈2n⌉m+n
≤ ( n − 1 ) m + n \le (n-1)m+n ≤(n−1)m+n
当 n ≤ m n \le m n≤m时,
l i m ≤ ( n − 1 ) m + m = n m lim \le (n-1)m+m=nm lim≤(n−1)m+m=nm
所以可以满足题目的要求。当 n > m n > m n>m时,我们就将整个矩阵转置后再进行处理,最后输出答案时不要忘记要将行列反着输出。
复杂度: O ( n m ) O(nm) O(nm)
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<sstream>
#include<ctime>
//#include<chrono>
//#include<random>
//#include<unordered_map>
using namespace std;
#define ll long long
#define ls o<<1
#define rs o<<1|1
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
const double pi=acos(-1.0);
const double eps=1e-6;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int maxn=105;
ll read(){
ll x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int t,n,m,lim;
int a[maxn][maxn];
char s[maxn];
struct edge{
int v,nop;
};
vector<edge>g[20];
vector<int>op[20];
queue<int>q;
int vis[20];
vector<int>pre[20];
vector<vector<pii> >ans;
int b[maxn][maxn];
void build(){
lim=4;
for(int i=1;i<(1<<lim);i++){
int base=(1<<lim)-1;
for(int j=0;j<4;j++){
int tmp=base^(1<<j);
int v=i^tmp;
g[v].pb((edge){i,j});
}
}
}
void bfs(){
q.push(0);
vis[0]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(auto e:g[u]){
if(vis[e.v])continue;
vis[e.v]=1;
q.push(e.v);
pre[e.v].assign(pre[u].begin(),pre[u].end());
pre[e.v].pb(e.nop);
}
}
}
void print(vector<pii>ve,int nop){
vector<pii>v;
for(int i=0;i<4;i++){
if(i!=nop){
v.pb(ve[i]);
}
}
ans.pb(v);
}
void init(){
build();
bfs();
for(int i=1;i<(1<<lim);i++){
reverse(pre[i].begin(),pre[i].end());
}
}
int trans(vector<pii>ve){
int sta=0;
for(int i=0;i<sz(ve);i++){
if(a[ve[i].fi][ve[i].se]){
sta|=(1<<i);
}
}
return sta;
}
void solve(vector<pii>ve){
int sta=trans(ve);
for(int i=0;i<sz(pre[sta]);i++){
print(ve,pre[sta][i]);
}
for(int i=0;i<sz(ve);i++){
a[ve[i].fi][ve[i].se]=0;
}
}
int main(void){
// freopen("in.txt","r",stdin);
init();
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++){
a[i][j]=s[j]-'0';
}
}
int rev=0;
if(n>m){
rev=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
b[i][j]=a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[j][i]=b[i][j];
}
}
swap(n,m);
}
vector<pii>ve,v;
ans.clear();
for(int i=1;i<=n;i+=2){
if(i==n)i--;
for(int j=1;j<=m-2;j++){
int cnt=a[i][j]+a[i+1][j];
if(cnt==0)continue;
if(cnt==1){
if(a[i][j]){
a[i][j]=0;
a[i][j+1]^=1;
a[i+1][j+1]^=1;
v.clear();
v.pb(mp(i,j));
v.pb(mp(i,j+1));
v.pb(mp(i+1,j+1));
ans.pb(v);
}
else{
a[i+1][j]=0;
a[i][j+1]^=1;
a[i+1][j+1]^=1;
v.clear();
v.pb(mp(i+1,j));
v.pb(mp(i,j+1));
v.pb(mp(i+1,j+1));
ans.pb(v);
}
}
else{
a[i][j]=a[i+1][j]=0;
a[i][j+1]^=1;
v.clear();
v.pb(mp(i,j));
v.pb(mp(i+1,j));
v.pb(mp(i,j+1));
ans.pb(v);
}
}
ve.clear();
ve.pb(mp(i,m-1));
ve.pb(mp(i,m));
ve.pb(mp(i+1,m-1));
ve.pb(mp(i+1,m));
solve(ve);
}
printf("%d\n",sz(ans));
for(int i=0;i<sz(ans);i++){
for(int j=0;j<sz(ans[i]);j++){
if(!rev)
printf("%d %d ",ans[i][j].fi,ans[i][j].se);
else{
printf("%d %d ",ans[i][j].se,ans[i][j].fi);
}
}
puts("");
}
}
return 0;
}