大家好,我是学习竞赛一年半的超级小周,喜欢唱,跳,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相似。

这题主要考察的是简单的搜索和要想办法优化的匹配。当然,这题真的可以不用枚举去过(这就要用数学相关的知识),超级小周学识浅薄,就算知道也不能很好的解释出来。所以就给读者留下一些想象空间吧!

以后我还会多发题解,喜欢的话就多多支持我吧!!(逃)

02-10 13:57