大家好,我是学习竞赛一年半的超级小周,喜欢唱,跳,rap,篮球。下面我将为大家分析这题为什么只能用搜索+枚举()
首先,我们把搜索和枚举在脑海里划掉,这时我们会想到哪种方法?由于只能交换任意两列数字(对一行的数字来说只是交换两个数字)或把每行数字 00 变成 11 , 11 变成 00 (有规律的改变 00 , 11 个数),很容易想到用一个数组记录每一行 11 的个数(可以表示为每一行数字的和),将两个魔板每一行进行比较。如果发现两个魔板有一行的 11 的个数失配(就是 ii != jj && ii != mm - jj )就可以输出NO了。另外,在匹配过程中,如果匹配失败,我们会非常高兴的把那行数字 00 变成 11 , 11 变成 00 。这样,匹配完成之时,我们就可以任意去交换两列的位置,用暴力来判断是否可以让两魔板匹配,由于只有 00 , 11 ,我们很容易想到用map来辅助我们判断,我们甚至可以用哈希表( 00 , 11 想到了什么?二进制啊!)来节约时间。这样看来,我们离AC不远了...
真的不远了吗?错!认为能A的都是cxk,如果出现 00 的个数= 11 的个数,那我们就无法判断那行该不该转换了,那行就会出现两种情况。所以,愣着干啥啊,只能枚举啦!
枚举的代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int K,n,m, a[110][110],h[110],l[110];
int o[110][110];
bool juge[110],yes,pm;
int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
bool cmp(int x,int y)
{
for(int i=1;i<=n;++i)
if(o[i][x]!=a[i][y])return false;
return true;
}
void dfs(int p)
{
if(p>m){yes=false;return;}//如果一直都没找到,就返回啦
for(int i=1;yes&&i<=m;++i)
if(!juge[i]&&cmp(p,i))
{
juge[i]=true;
dfs(p+1);//搜索+回溯
juge[i]=false;
}
}
int main()
{
K=read();
while(--K>=0)
{
yes=true;
memset(h,0,sizeof(h));
memset(l,0,sizeof(l));
n=read();
m=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=read(),h[i]+=a[i][j];//记录1的个数
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
o[i][j]=read(),l[i]+=o[i][j];//记录1的个数
for(int i=1;yes&&i<=m;++i)
{
pm=true;
for(int j=1;pm&&j<=n;++j)
{
if(a[j][i]!=o[j][1])//反
{
for(int k=1;k<=m;++k)a[j][k]=a[j][k]^1;//^效率高
h[j]=m-h[j];
}
if(h[j]!=l[j])pm=false;//这里是判断上面说的i==j||i==m-j
}
if(!pm)continue;
juge[i]=true;
dfs(2);//开始搜
juge[i]=false;
}
if(yes)printf("NO\n");
else printf("YES\n");
}
return 0;
}
咦?怎么A了?数据这么水?
这题的地方就在这,如果每行都有两种情况,那时间就会大大增加,这时打得不好的暴力枚举就差不多超时了(),那怎么办?...没看前面啊?用哈希表或map来辅助判断啊!
map格式
map<string,int> www;
string s;
s+='0'或'1';
...
一列存完后。。。
www[s]=1;
查找...
每次用完记得清空
哈希是我大胆提出的一个思路,因为只有01很容易想到2进制,显然不会冲突
由于数据2的100次方超出限制,我们可以以四个长度>=25的数组分别求哈希值,再判断。步骤与map相似。
这题主要考察的是简单的搜索和要想办法优化的匹配。当然,这题真的可以不用枚举去过(这就要用数学相关的知识),超级小周学识浅薄,就算知道也不能很好的解释出来。所以就给读者留下一些想象空间吧!
以后我还会多发题解,喜欢的话就多多支持我吧!!(逃)