题意:
略略略
ABCED
BDACE
EBBAA
上面式子的意思是:
第一行和第二行是加数,第三行是结果。
并且这是n进制加法,每个字母代表0--n-1中一个。
字母和数字一一对应。
这个的结果是1 0 3 4 2
即
10324
04132
20011
(允许有前导0)
10进制加法是满十进一,N进制加法是满n进1.
(4+2)%5=1;(2+3+1)%5=1;......
题解:
一、数组:
ans[]记录答案,ans[0]代表A对应的数字,开始赋值为-1.
不能赋值为0,因为0可以为对应的数字。
use[]标记数字是否被占用。use[0]=true,表示数字0已经赋值给别的字母了。
二、剪枝:
先来几个普通的剪枝,(如果想看更多剪枝就看其他题解吧...)
1)首先是n位,所以最高位不能进1,否则结果是n+1位。
2)知二推一。
情况一:知道两个加数和结果(假设为a,b,c),我们可以算出结果为(a+b)%n。
但我们不知道之前是否有进位。那么如果c既不等于(a+b)%n,也不等于(a+b+1)%n,
那么c一定是不对的了。
情况二:知道c和a,b中的一个,假设知道b,那么a=c-b。若a<0,a+=n;
如果现在推出的a这个数已经被其他字母占用了,并且a-1(有进位)不存在,即<0,
或者存在但也被其他字母占用了,那么就没有数字对应这个字母,需要return。
三、搜索顺序(各个顺序的代码和所用时间后面会给出)
1)按顺序,从A开始搜每个字母代表的数字。
2)按照我们手推的顺序,从左到右,从上到下,以列一列的搜。
3)跟第二种差不多..或者一楼的next数组就是这个意思?【笑
在做靶形数独这个题时,有一种搜的方法是把没填的格子位置记录下来,
在搜时从当前没填的格子直接跳到下一个没填的格子,不用遍历整张图。
我们按手推的顺序(上到下,左到右)把遇到的一个个字母装入一个数组中。
不是从A、B、C....搜,而是从我们手推遇到字母的顺序搜。
如样例:搜索顺序就是DEACB...
时间和第二种顺序差不多
4)倒着搜...玄学
四、代码
【代码一】70 3740ms 从A搜
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n; char s1[30],s2[30],s3[30]; int A[30],B[30],C[30]; bool use[30]; int ans[30]; void print() { for(int i=0;i<n;i++) printf("%d ",ans[i]); exit(0); } bool ok() { int x=0; for(int i=n;i>=1;i--) { int a=ans[A[i]],b=ans[B[i]],c=ans[C[i]]; if((a+b+x)%n!=c)return false; x=(a+b+x)/n; } return true; } bool check() { for(int i=n;i>=1;i--) { int a=ans[A[i]],b=ans[B[i]],c=ans[C[i]]; if(i==1&&a+b>n)return false; if(a!=-1&&b!=-1&&c!=-1) { if((a+b)%n!=c&&(a+b+1)%n!=c) return false; } if(a==-1&&b!=-1&&c!=-1) { int d=c-b; if(d<0)d+=n; if(use[d]&&use[d-1])return false; } if(a!=-1&&b==-1&&c!=-1) { int d=c-a; if(d<0)d+=n; if(use[d]&&use[d-1])return false; } } return true; } void dfs(int now) { if(now==n) { if(ok())print(); return; } if(check()==false)return; for(int i=0;i<n;i++) { if(!use[i]) { use[i]=true; ans[now]=i; dfs(now+1); use[i]=false; ans[now]=-1; } } } int main() { scanf("%d",&n); scanf("%s%s%s",s1+1,s2+1,s3+1); for(int i=1;i<=n;i++) { A[i]=s1[i]-'A'; B[i]=s2[i]-'A'; C[i]=s3[i]-'A'; } for(int i=0;i<n;i++)ans[i]=-1; dfs(0); return 0; }
【代码二】按手推顺序搜 94ms
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n; int pos[4][40]; int ans[30]; char s1[30],s2[30],s3[30]; bool use[30]; void print() { for(int i=0;i<n;i++) printf("%d ",ans[i]); exit(0); } bool ok() { int x=0; for(int i=n;i>=1;i--) { int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]]; int xx=a+b+x; if(xx%n!=c) return false; x=xx/n; } return true; } bool check() { if(ans[pos[1][1]]+ans[pos[2][1]]>=n) return false; for(int i=1;i<=n;i++) { int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]]; if(a!=-1&&b!=-1&&c!=-1) { if((a+b)%n!=c&&(a+b+1)%n!=c) return false; } if(a!=-1&&b==-1&&c!=-1) { int d=c-a; if(d<0) d+=n; if(use[d]&&(d-1<0||use[d-1])) return false; } if(a==-1&&b!=-1&&c!=-1) { int d=c-b; if(d<0)d+=n; if(use[d]&&(d-1<0||use[d-1])) return false; } } return true; } void dfs(int x,int y,int has) { if(has==n) { if(ok()) print(); return; } if(check()==false) return; if(y==0) return ; if(ans[pos[x][y]]!=-1) { if(x==3) dfs(1,y-1,has); else dfs(x+1,y,has); }else { for(int i=n-1;i>=0;i--) { if(!use[i]) { use[i]=true; ans[pos[x][y]]=i; if(x==3)dfs(1,y-1,has+1); else dfs(x+1,y,has+1); use[i]=false; ans[pos[x][y]]=-1; } } } } int main() { scanf("%d",&n); scanf("%s%s%s",s1+1,s2+1,s3+1); for(int i=1;i<=n;i++) { pos[1][i]=s1[i]-'A'; pos[2][i]=s2[i]-'A'; pos[3][i]=s3[i]-'A'; } for(int i=0;i<n;i++)ans[i]=-1; dfs(1,n,0); return 0; }
【代码三】 91ms 这样搜仿佛没什么卵用 :-)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,cnt; int pos[4][30],k[30],ans[30]; char s1[30],s2[30],s3[30]; bool use[30]; void print() { for(int i=0;i<n;i++) printf("%d ",ans[i]); exit(0); } bool ok() { int x=0; for(int i=n;i>=1;i--) { int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]]; int xx=a+b+x; if(xx%n!=c) return false; x=xx/n; } return true; } bool check() { if(ans[pos[1][1]]+ans[pos[2][1]]>=n) return false; for(int i=1;i<=n;i++) { int a=ans[pos[1][i]],b=ans[pos[2][i]],c=ans[pos[3][i]]; if(a!=-1&&b!=-1&&c!=-1) { if((a+b)%n!=c&&(a+b+1)%n!=c) return false; } if(a!=-1&&b==-1&&c!=-1) { int d=c-a; if(d<0) d+=n; if(use[d]&&(d-1<0||use[d-1])) return false; } if(a==-1&&b!=-1&&c!=-1) { int d=c-b; if(d<0)d+=n; if(use[d]&&(d-1<0||use[d-1])) return false; } } return true; } void dfs(int now) { if(now==n+1) { if(ok()) print(); return ; } if(check()==false) return; for(int i=n-1;i>=0;i--) { if(use[i]) continue; int anow=k[now]; use[i]=true; ans[anow]=i; dfs(now+1); use[i]=false; ans[anow]=-1; } } int main() { scanf("%d",&n); scanf("%s%s%s",s1+1,s2+1,s3+1); for(int i=n;i>=1;i--) { pos[1][i]=s1[i]-'A'; if(!use[pos[1][i]])k[++cnt]=pos[1][i],use[pos[1][i]]=true; pos[2][i]=s2[i]-'A'; if(!use[pos[2][i]])k[++cnt]=pos[2][i],use[pos[2][i]]=true; pos[3][i]=s3[i]-'A'; if(!use[pos[3][i]])k[++cnt]=pos[3][i],use[pos[3][i]]=true; } memset(use,0,sizeof(use)); memset(ans,-1,sizeof(ans)); dfs(1); return 0; }