题目链接:https://www.luogu.org/problem/show?pid=1092
解:
我真的交了好多遍。。
开始,用getchar()一个个字母读入,0分。。。
改成scanf(),70,并且在70的道路上一发不可收拾。。。
后来看了别人的代码才发现,原来我们的枚举是要进行优化的。。。
解:
70分做法:先枚举每个字母代表的数字,然后枚举一个,判断一次,如果一列上的三个字母都有代表的数字了,就判断合不合法,枚举所有的列。最后枚举完后检查一遍。
100分做法:在上一个做法的情况下我们不要从‘A’~‘Z’来一个个枚举代表的数字,而是按照输入的顺序来,我们开一个数组,一列列扫过三个字符串,如果这个字符没在数组里,就把它加进去。最后按照数组中的字母的顺序来进行枚举。很显然按这个枚举方式,更容易在判断的时候时间较短地找到错误,因为两个都是一列列扫的。至于从前往后还是从后往前,就需要与判断时候扫的顺序一致。
程序:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstdlib> #include<cstring> using namespace std; int n,num[30],a[30],b[30],c[30],cnt,po[30]; char a1[30],b1[30],c1[30]; bool vis[30],bl[100]; void write() { for (int i=0;i<=n-2;i++) printf("%d ",num[i]); if (n!=0) printf("%d\n",num[n-1]); exit(0); } bool check() { for (int i=n;i>=1;i--) if ((num[a[i]]!=-1)&&(num[b[i]]!=-1)&&(num[c[i]]!=-1) &&(((num[a[i]]+num[b[i]])%n)!=num[c[i]])&&(((num[a[i]]+num[b[i]]+1)%n)!=num[c[i]])) return false; return true; } bool check2() { int ef=0; for (int i=n;i>=1;i--) { int l=num[a[i]]+num[b[i]]+ef; if ((l%n)!=num[c[i]]) return false; ef=l/n; } return true; } void dfs(int now) { if ((num[a[1]]+num[b[1]])>n-1) return; if (!check()) return; if (now==n) {if (check2()) write();} for (int j=n-1;j>=0;j--) if (!vis[j]) { num[po[now]]=j; vis[j]=true; dfs(now+1); vis[j]=false; num[po[now]]=-1; } } int main() { scanf("%d",&n); scanf("%s%s%s",a1,b1,c1); char ch; for (int i=0;i<=n;i++) num[i]=-1; for (int i=1;i<=n;i++) { a[i]=a1[i-1]-'A'; b[i]=b1[i-1]-'A'; c[i]=c1[i-1]-'A'; } for (int i=n-1;i>=0;i--) { if (!bl[a1[i]]) {po[cnt++]=a[i+1];bl[a1[i]]=true;} if (!bl[b1[i]]) {po[cnt++]=b[i+1];bl[b1[i]]=true;} if (!bl[c1[i]]) {po[cnt++]=c[i+1];bl[c1[i]]=true;} if (cnt==n) break; } dfs(0); return 0; }