翻硬币(搜索)

题目大意

有一个n*m的格子,每个格子上有一个硬币,用0表示正面朝上,1表示反面朝上。
一次操作你可以将一行或一列的硬币都反转,问你是否能够进行一系列的操作之后使得所有的硬币都朝上。

分析

这道题和黑白棋那道类似,黑白棋那道有个启发式信息是一个点不会反转超过一次,这道题也是同样的道理,一行或一列不会反转超过一次。
然后我们观察一种可能的反转情况:
这里写图片描述
我们可以发现这样的信息:反转的情况类似于“井”状,并且出于交叉出的点一定是0,因为只有0点在反转两次后才会依然朝上。

继续观察我们发现了一条有用的信息:
一种可行的反转操作集合的补集也一定是可行的,如下图:
这里写图片描述

这样,我们不妨将第一行反转,对于第一行中为0的点我们将这些点所在的列也反转,做了这样一个初始操作之后我们继续看后面的行,后面不可能在进行列反转操作了,因为这会破坏第一行的状态,所以我们只需要去统计后面每一行是否都是相同的数就行了。

还有需要注意的一点就是题目中给的图范围是n*m< 106 但并没有给n和m的范围,所以我们需要用一维数组去模拟二维数组,mat[x][y]用a[i]表示,其中i=(x-1)*m+y

代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<stack>
using namespace std;
const long long int INF=0x7fffffffffffffff;
const int MAXN= 1000005;
int a[MAXN];
int T;
int n,m;
bool  x_change[MAXN];//x_change[i]为1表示第i行反转,0表示不反转
bool  y_change[MAXN];
void Init()
{
      memset(a,0,sizeof(a));
      memset(x_change,0,sizeof(x_change));
      memset(y_change,0,sizeof(y_change));
}
bool Work()
{
    x_change[1]=1;
    for(int j=1;j<=m;j++)
    {
        if(a[j]==0)y_change[j]=1;
    }
    int cnt;//
    for(int i=1;i<=n;i++)//n行m列
    {
         cnt=0;//表示第i行有多少0
         for(int j=1;j<=m;j++)
         {
              int loc=(i-1)*m+j;
              if(a[loc]==0 && y_change[j]==0)cnt++;
              if(a[loc]==1 && y_change[j]==1)cnt++;
         }
         if(cnt>0 && cnt<m)return 0;
    }
    return 1;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
          Init();
          scanf("%d%d",&n,&m);
          for(int i=1;i<=n;i++)
          {
                for(int j=1;j<=m;j++)
                {
                    scanf("%d",&a[(i-1)*m+j]);
                }
          }
          if(Work()==1)printf("YES\n");
          else printf("NO\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值