您的位置:首页 > 其它

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

2016-09-22 11:22 435 查看

题目描述

传送门

题解

一看这就是爆搜题嘛,据说有人说高斯消元才是正解戳这里

但是这个爆搜的技巧还是很多的,让我学到了有用的东西:

①每搜出来一个数都要判断是否合法。这样看起来每次都要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);
}


总结

①分析性质!分析性质!分析性质!非常重要!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: