luogu P1275 魔板 题解

题面
题意:给你两个n×m的01矩阵,每次可以对其中一个矩阵进行交换两列,或者反转某一行(0变1,1变0)的 操作,问两个矩阵是否能互相转化。

首先我们只考虑对第一个矩阵进行操作,让它变成第二个矩阵。
我们考虑无论第一个矩阵如何变换,最终都需要有一列变得和第二个矩阵的第一列一样,而如果我们强制某一列变得和第二个矩阵的第一列一样的话,那么所有行上的异或操作的状态就确定了,这样我们就只需要将剩下的m-1列进行匹配就可以了。
所以我们枚举每一列与第二个矩阵的第一列匹配,将不同的行全部反转,然后检查一下这m列能不能互相匹配。

代码(另一种做法,将两个矩阵都变成子典序最小的状态,然后判断是否相同):

#include<bits/stdc++.h>
using namespace std;
#define N 107
char g[N][N];
int n,m;
void swp(int x,int y)
{
	for(int i=1;i<=n;i++)
		swap(g[i][x],g[i][y]);
}
void chg(int x)
{
	for(int i=1;i<=m;i++)
		g[x][i]^=1;
}
string s[N];
string solve()
{
	string ret="";
	for(int o=1;o<=m;o++)
	{
		swp(o,1);
		for(int i=1;i<=n;i++)
			if(g[i][1]=='1')chg(i);
		for(int i=2;i<=m;i++)
		{
			s[i]="";
			for(int j=1;j<=n;j++)
				s[i]+=g[j][i];
		}
		sort(s+2,s+m+1);
		string t="";
		for(int i=2;i<=m;i++)
			t+=s[i];
		if(o==1)ret=t;
		else ret=min(ret,t);
	}
	return ret;
}
int main()
{
	int T;
	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("%s",&g[i][j]);
		string s1=solve();
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				scanf("%s",&g[i][j]);
		string s2=solve();
		if(s1==s2)printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}
posted @ 2020-01-03 08:52  lyyi2003  阅读(147)  评论(0编辑  收藏  举报