[NOIP2004][CODEVS1064]虫食算(搜索||高斯消元)

来源:互联网 发布:手机淘宝扫码 编辑:程序博客网 时间:2024/06/06 01:03

题目描述

传送门

题解

一看这就是爆搜题嘛,据说有人说高斯消元才是正解戳这里
但是这个爆搜的技巧还是很多的,让我学到了有用的东西:
①每搜出来一个数都要判断是否合法。这样看起来每次都要O(n)扫一遍,但是效果却非常好,可以剪掉大量的废枝。对于判断,我刚开始只考虑了没有进位的部分,有进位的部分不进行判断,这样的话实际上非常没用。那么如果要考虑到进位的问题,A+B=C的话,如果(A+B)%n!=C且(A+B+1)%n!=C,那么ABC一定不是合法解。并且如果知道了ABC其中的两个,那么可以算出第三个,并且也要分进位和不进位两种情况,如果两种情况算出来的数之前都用过,那么这组解也不合法。
②判断合法的方式提醒我们,对于每一项,ABC知道得越多越容易被剪枝。那么可以改变搜索的顺序,按照字母从右往左出现的顺序搜索。这个效果也非常明显。
③填数的时候倒序搜比正序搜要快很多。why?

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>using namespace std;char a[30],b[30],c[30],s[100];int n,len,ans[30];bool vis[30];bool check(){    int last=0,aa,bb,cc;    for (int i=n-1;i>=0;--i)    {        aa=ans[a[i]-'A'+1],bb=ans[b[i]-'A'+1],cc=ans[c[i]-'A'+1];        if (aa==-1||bb==-1||cc==-1) {last=-1;continue;}        if (last==-1)        {            if ((aa+bb)%n!=cc&&(aa+bb+1)%n!=cc) return false;        }        else        {            if ((aa+bb+last)%n!=cc) return false;            last=(aa+bb+last)/n;        }       }    if (last!=-1&&last!=0) return false;    return true;}void dfs(int dep){    if (dep==len+1)    {        if (check())        {            for (int i=1;i<=n;++i) printf("%d%c",ans[i]," \n"[i==n]);            exit(0);        }        return;    }    int now=s[dep]-'A'+1;    if (ans[now]!=-1) dfs(dep+1);    else        for (int i=n-1;i>=0;--i)            if (!vis[i])            {                ans[now]=i;                vis[i]=true;                if (check())                    dfs(dep+1);                ans[now]=-1;                vis[i]=false;            }}int main(){    scanf("%d\n",&n);    gets(a); gets(b); gets(c);    for (int i=n-1;i>=0;--i)    {        if (!vis[a[i]-'A'+1]) vis[a[i]-'A'+1]=true,s[++len]=a[i];        if (!vis[b[i]-'A'+1]) vis[b[i]-'A'+1]=true,s[++len]=b[i];        if (!vis[c[i]-'A'+1]) vis[c[i]-'A'+1]=true,s[++len]=c[i];    }    memset(ans,-1,sizeof(ans)); memset(vis,0,sizeof(vis));    dfs(1);}

总结

①分析性质!分析性质!分析性质!非常重要!!!

0 0
原创粉丝点击