洛谷P1275 魔板
题目描述
有这样一种魔板:它是一个长方形的面板,被划分成n行m列的n*m个方格。每个方格内有一个小灯泡,灯泡的状态有两种(亮或暗)。我们可以通过若干操作使魔板从一个状态改变为另一个状态。操作的方式有两种:
(1)任选一行,改变该行中所有灯泡的状态,即亮的变暗、暗的变亮;
(2)任选两列,交换其位置。
当然并不是任意的两种状态都可以通过若干操作来实现互相转化的。
你的任务就是根据给定两个魔板状态,判断两个状态能否互相转化。
输入输出格式
输入格式:
文件中包含多组数据。第一行一个整数k,表示有k组数据。
每组数据的第一行两个整数n和m。(0<n,m≤100)
以下的n行描述第一个魔板。每行有m个数字(0或1),中间用空格分隔。若第x行的第y个数字为0,则表示魔板的第x行y列的灯泡为“亮”;否则为“暗”。
然后的n行描述第二个魔板。数据格式同上。
任意两组数据间没有空行。
输出格式:
共k行,依次描述每一组数据的结果。
若两个魔板可以相互转化,则输出YES,否则输出NO。(注意:请使用大写字母)
输入输出样例
输入样例#1:
2 3 4 0 1 0 1 1 0 0 1 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 0 2 2 0 0 0 1 1 1 1 1
输出样例#1:
0分 手模不出样例,我自己写的宽搜也没过
100分
YES NO
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<queue> #define maxn 110 #define mod 10000003 using namespace std; map<string,bool>vis; int n,m,T,a[10001]; string t; string s,cur,nxt; queue<string>q; string hash(int x[]){ string res=""; for(int i=1;i<=n*m;i++)res+=x[i]+'0'; return res; } bool bfs(){ while(!q.empty()){ cur=q.front();q.pop(); for(int i=1;i<=n;i++){//枚举修改每一行 int w=(i-1)*m; nxt=cur; for(int j=0;j<m;j++){ if(nxt[w+j]=='0')nxt[w+j]='1'; else nxt[w+j]='0'; } if(nxt==t)return 1; if(!vis[nxt]){ q.push(nxt); vis[nxt]=1; } } for(int i=0;i<m;i++){//枚举修改每一列 nxt=cur; for(int j=0;j<m;j++){ if(nxt[i+j*m]=='0')nxt[i+j*m]='1'; else nxt[i+j*m]='0'; } if(nxt==t)return 1; if(!vis[nxt]){ q.push(nxt); vis[nxt]=1; } } } return 0; } int main(){ scanf("%d",&T); while(T--){ while(!q.empty())q.pop(); s="";t=""; //memset(vis,0,sizeof(vis)); vis.clear(); scanf("%d%d",&n,&m); for(int i=0;i<n*m;i++){ scanf("%d",&a[i]); s+=a[i]+'0'; } for(int i=0;i<n*m;i++){ scanf("%d",&a[i]); t+=a[i]+'0'; } vis[s]=1; q.push(s); if(bfs())printf("YES\n"); else printf("NO\n"); } }
/* 第一步:在最外层循环枚举初始的每一列当做目标状态的第一列 第二步:在每层循环中比较当前这列和目标状态的第一列的同行的数,如果不相同则把初始的那一行翻转(前面先记录,后面记得还原) 第三步:看看剩下的列是否可以一一对应,如果可以就yes,不可以就继续枚举。 */ #include<iostream> #include<cstdio> #include<cstring> using namespace std; #define maxn 110 int n,m,T,s[maxn][maxn],t[maxn][maxn]; bool change_x[maxn],vis_y[maxn]; bool check(int x){ memset(change_x,0,sizeof(change_x)); memset(vis_y,0,sizeof(vis_y)); for(int i=1;i<=n;i++) if(s[i][x]!=t[i][1]) change_x[i]=1;//第i行需要翻转 vis_y[x]=1; for(int i=2;i<=m;i++){//目标状态的第i列 bool flag=0; for(int j=1;j<=m;j++){//初始状态的第j列 if(vis_y[j])continue; int cnt=0; for(int k=1;k<=n;k++){ if((change_x[k]&&s[k][j]!=t[k][i])||(!change_x[k]&&s[k][j]==t[k][i]))cnt++; else break; } if(cnt==n){ vis_y[j]=1,flag=1; break; } } if(!flag)return 0; } return 1; } int main(){ freopen("Cola.txt","r",stdin); scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&s[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&t[i][j]); bool flag=0; for(int i=1;i<=m;i++){//枚举初始状态的每一列与目标状态对应 int now=check(i); if(now==1){ printf("YES\n"); flag=1;break; } } if(!flag)printf("NO\n"); } }