luogu P1275 魔板 题解

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

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

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

#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;
}

猜你喜欢

转载自www.cnblogs.com/lishuyu2003/p/12142459.html