【洛谷】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。(注意:请使用大写字母)

输入输出样例

输入
  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

输出

  YES

  NO

分析

  一直以为是个结论题没想到居然是个暴力枚举的。。。。。。

  先来手玩一下就可以发现(并不,所以每行最多只有可能变换一次,不然就换回来了。

  所以每一行就会有两种情况,变和不变

  然后yyq暴力2^n枚举每行的变化情况加剪枝大力出奇迹过了这个题

 

  其实除了2^n枚举之外,还有一种枚举方法

  对于每一列来说,列的变换不会改变数字

  先假设能成功

  那么如果我们知道第1个矩阵中的某一列经过变换后成为第2个矩阵的某一列,

  那我们就可以通过比较两个列哪些数字不同,推出哪些行是变换了的

  所以我们直接去枚举第1个矩阵中的第一列经过变换后成为第2个矩阵的第i列

  然后推出哪些行是变换了,进而n^3判断剩下的列是否可行。

  如果全都不行则无解

  复杂度是O(kn^4),开开O2应该可以过

  我不信你100张牌能秒我???(雾

  代码

#include<cstdio>
#include<cstring>
int T,n,m,rev[105],vis[105],nw[105][105],nx[105][105];
bool check(int x)
{
    memset(vis,0,sizeof vis);vis[x]=1;
    for(int j=2;j<=m;j++)
    {
        int flag=0;
        for(int k=1;k<=m;k++)if(!vis[k])
        {
            flag=1;
            for(int i=1;i<=n;i++)flag&=(nw[i][j]==(rev[i]^nx[i][k]));
            if(flag){vis[k]=1;break;}
        }
        if(!flag)return 0;
    }
    return 1;
}
int main()
{
    for(scanf("%d",&T);T;T--)
    {
        scanf("%d%d",&n,&m);int flag=0;
        for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&nw[i][j]);
        for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&nx[i][j]);
        for(int i=1;i<=m&&!flag;i++)
        {
            memset(rev,0,sizeof rev);
            for(int j=1;j<=n;j++)rev[j]=(nw[j][1]!=nx[j][i]);
            flag=check(i);
        }
        if(flag)puts("YES");else puts("NO");
    }
}   
原文地址:https://www.cnblogs.com/firecrazy/p/11654590.html