关于魔板题解

关于魔板题解

焦祺 08-12-3

Problem Description

有这样一种魔板:它是一个长方形的面板,被划分成nm列的n*m个方格。每个方格内有一个小灯泡,灯泡的状态有两种(亮或暗)。我们可以通过若干操作使魔板从一个状态改变为另一个状态。操作的方式有两种:
1)任选一行,改变该行中所有灯泡的状态,即亮的变暗、暗的变亮;
2)任选两列,交换其位置。
当然并不是任意的两种状态都可以通过若干操作来实现互相转化的。
你的任务就是根据给定两个魔板状态,判断两个状态能否互相转化。

Input

包含多组数据。第一行一个整数k,表示有k组数据。
每组数据的第一行两个整数nm(0<nm≤100)
以下的n行描述第一个魔板。每行有m个数字(01),中间用空格分隔。若第x行的第y个数字为0,则表示魔板的第xy列的灯泡为;否则为

然后的n行描述第二个魔板。数据格式同上。任意两组数据间没有空行。

Output

k行,依次描述每一组数据的结果。
若两个魔板可以相互转化,则输出YES,否则输出NO(注意:请使用大写字母)

Sample Input

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

Sample Output

YES

NO


题目一拿到手,我就觉得状态可能有点庞大,于是先手算了一下题目的状态量。

题目中,最大的魔板是100*100,每一种魔板可以扩展出A = N+(M-1)!种可能,可以扩展的深度可能为:B = (2^N) * (M-1)! 于是可能出现的最大状态为A^B

A~100!差不多有160位,B~30+160位数,于是A^B约为160*190~30000多位数的状态。(或许算错了~~)我一开始就把它看成是广搜来考虑,所以可能会TLE

后来看了下别人的解题思路才豁然开朗。

 

【网上解题思路】
 
这道题是一道典型的深搜题,我们可以比较容易的想到思路,但是我们要想优化算法,就必须进行一些小处理,我们可以枚举每一列作为第一列,再和目标状态比较,把每一个不同的行进行反处理,然后我们就可以把剩下的列进行不同的排列,看能否找到一种符合目标状态的排列,这样一来,我们可以大大的降低搜索深度,对于题目的NM,就可以承受了。

 

不过看起来简单,做起来没有那么容易

刚开始写完没有那么自信,提交后不出所料TLE了!

稍作修改之后又变成了WA,这让我失去信心

问了下大牛,说是那排序的方法,这让我眼睛一亮!

但大牛试写了一下也写不下去了。

那个魔板的题我用排序的方法再想了一下,虽然是个好的方法,但01数相等的时候不能很好的处理,它们是和其它列相关联的,所以用排序的方法不好解决!

于是我抱着微弱的希望,再次修改我的程序,没想到这次RP大暴发,93MS AC

 

这道题也给了我一个启示:

对问题的求解时要注意,在得出解法的时候也要注意想想有没有更优更好的解法,思维要发散一些,不要因为搜索就要用搜索的方法去完成。

 

AC代码:

 

#include <iostream>

using namespace std;

struct NODE

{

       int node[102][102];

};

NODE temp,start,end;

int main()

{

       int i,j,k,t,n,m,top;

       while (scanf("%d",&t) != EOF)

       {

              while (t--)

              {

                     scanf("%d %d",&n,&m);

                     for (i=0;i<n;i++)

                     {

                            for (j=0;j<m;j++)

                            {

                                   scanf("%d",&start.node[i][j]);

                            }

                     }

                     for (i=0;i<n;i++)

                     {

                            for (j=0;j<m;j++)

                            {

                                   scanf("%d",&end.node[i][j]);

                            }

                     }

 

                     //--------------------------------------------------

                     //开始枚举每一列作为第一列再和目标状态比较

                     top = 0; int row[102]; int j0,j1;int flag[102];

                     for (j0=0;j0<m;j0++)

                     {

                            temp = start;

                            if (j0!=0)

                            {

                                   for (i=0;i<n;i++)     //枚举每一列作为第一列

                                   {

                                          row[i] = temp.node[i][j0];

                                          temp.node[i][j0] = temp.node[i][0];

                                          temp.node[i][0] = row[i];

                                   }

                            }

                            for (i=0;i<n;i++)            //目标状态比较

                            {

                                   if (temp.node[i][0] != end.node[i][0])//把每一个不同的行进行反处理

                                   {

                                          for (j=0;j<m;j++)

                                          {

                                                 if (temp.node[i][j] == 0)

                                                 {

                                                        temp.node[i][j] = 1;

                                                 }

                                                 else

                                                        temp.node[i][j] = 0;

                                          }

                                   }

                            }

                            //把剩下的列进行不同的排列,看能否找到一种符合目标状态的排列

                            memset(flag,0,sizeof(flag));

                            for (j=1;j<m;j++)

                            {

                                   for (j1=1;j1<m;j1++)

                                   {

                                          if (flag[j1] == 1)

                                                 continue;

                                          for (i=1;i<n;i++)

                                          {

                                                 if (temp.node[i][j] != end.node[i][j1])

                                                        break;

                                          }

                                          if (i == n)

                                          {

                                                 flag[j1] = 1;

                                                 break;

                                          }

                                   }

                            }

                            for (j=1;j<m;j++)

                            {

                                   if (flag[j] == 0)

                                   {

                                          break;            //没有找到

                                   }

                            }

                            if (j == m)

                            {

                                   printf("YES/n");

                                   break;

                            }

                     }

                     if (j0 == m)

                     {

                            printf("NO/n");

                     }

              }

       }

       return 0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值