[NOIP2004提高组]虫食算(搜索剪枝)
30pts:善用next_permutation
50pts:先枚举每一位是否有进位,设进位为di=0/1,然后a[i]+b[i]+d[i-1]-10d[i]=c[i],移项后为a[i]+b[i]-c[i]=10d[i]-d[i-1],n位形成n个方程组,可以进行高斯消元,时间复杂度O(2^n*n^3)
100pts:高斯消元是一个死胡同,但似乎也有这种方法做出来的,但我太菜了学不会。
改用搜索剪枝。实际上很多状态搜了一点点就会发现它是错的。于是从低位向高位枚举字母,每次枚举后就判断是否可行,不可行就不再往下搜索,这样可以搜过去。
#include<bits/stdc++.h> using namespace std; int n,cnt,s[300],used[30],p[30]; char a[30],b[30],c[30]; bool check() { for(int i=n;i;i--) if(s[a[i]]!=-1&&s[b[i]]!=-1&&s[c[i]]!=-1&&(s[a[i]]+s[b[i]])%n!=s[c[i]]&&(s[a[i]]+s[b[i]]+1)%n!=s[c[i]]) return 0; return 1; } void work() { int jw=0,sum; for(int i=n;i;i--) { sum=s[a[i]]+s[b[i]]+jw; if(s[c[i]]!=sum%n)return; jw=sum/n; } for(int i='A';i<'A'+n;i++)printf("%d ",s[i]); exit(0); } void dfs(int u) { if(u>n){work();return;} for(int i=n-1;~i;i--) if(!used[i]) { s[p[u]+'A'-1]=i; if(check()){used[i]=1;dfs(u+1);used[i]=0;} } s[p[u]+'A'-1]=-1; } int main() { scanf("%d",&n); scanf("%s%s%s",a+1,b+1,c+1); memset(s,-1,sizeof s); for(int i=n;i;i--) { if(!used[a[i]-'A'+1])p[++cnt]=a[i]-'A'+1,used[a[i]-'A'+1]=1; if(!used[b[i]-'A'+1])p[++cnt]=b[i]-'A'+1,used[b[i]-'A'+1]=1; if(!used[c[i]-'A'+1])p[++cnt]=c[i]-'A'+1,used[c[i]-'A'+1]=1; } memset(used,0,sizeof used); dfs(1); }