https://www.luogu.org/problem/show?pid=1092
题目描述
所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:
43#9865#045
+8468#6633
44445509678
其中#号代表被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5。
现在,我们对问题做两个限制:
首先,我们只考虑加法的虫食算。这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0。
其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。如果这个算式是N进制的,我们就取英文字母表午的前N个大写字母来表示这个算式中的0到N-1这N个不同的数字:但是这N个字母并不一定顺序地代表0到N-1)。输入数据保证N个字母分别至少出现一次。
BADC
- CBDA
DCCC 上面的算式是一个4进制的算式。很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。你的任务是,对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解
输入输出格式
输入格式:
包含四行。第一行有一个正整数N(N<=26),后面的3行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。
输出格式:
包含一行。在这一行中,应当包含唯一的那组解。解是这样表示的:输出N个数字,分别表示A,B,C……所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。
输入输出样例
5 ABCED BDACE EBBAA
1 0 3 4 2
说明
对于30%的数据,保证有N<=10;
对于50%的数据,保证有N<=15;
对于全部的数据,保证有N<=26。
最暴力的搜索:枚举每个字母代表什么,检验
优化:
O、对于当前列的三个字符是否已经确定分8种情况讨论
(3个都确定,确定2个*3,只确定1个*3,都没确定)
1、3个都确定的,直接判断
2、确定了2个的,推出第3个
3、只确定1个的,枚举一个,推出另一个
4、都没确定的,枚举前两个,推第三个,这样可以不用枚举是否进位
A、对于搜索顺序的优化:
1、小学算竖式?从右往左算! 所以按竖式从右往左枚举,低位的进位对高位有影响
2、枚举字母代表的数字从n-1往小枚举,因为最高位不会进位,高位比较小(优化的关键)
B、一般都能想到的优化:
1、用一个数组,记录这个数字是否已经被用过(代码中的use[])
2、一旦结果搜出来了,设标志变量,一路return之至主函数,最好在每个递归回溯前都写一个。(exit(0)也可以,但不确定NOIP可不可以用)
C、进位的优化:
1、用一个数组记录当前位是否进位,代码中的bit[]
2、如果这一列的左边一列3个数都齐了,判断在满足他们的情况下,这一列是否需要进位
D、剪枝的关键:
枚举这一列左边的列,如果他们3个数都齐了,判断在进位/不进位的情况下是否成立,不成立则return
没有这个剪枝过不了第9个点
注意(我犯的错误):
1、并不是同一列中的三个字母代表数字都不能相同,需要判断一下有没有重复字母
这种情况只会影响确定1个 和 都没确定得到情况
对于只确定1个字母的列,只需要判断枚举出的数是否出现过即可
对于3个字母都没确定的列,在枚举前两个的时候要判断前两个字母是否相等
2、低位往高位进1,高位算的时候不是想当然的10啊,是n,这是n进制
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n; char a[30],b[30],c[30]; int ans[30]; bool ok,use[30],bit[30]; inline void dfs(int now) { if(ok) return; if(now<0) { for(int i=0;i<n;i++) printf("%d ",ans[i]); ok=true; return; } int flag=2; if(now && ans[a[now-1]-'A']!=-1 && ans[b[now-1]-'A']!=-1 && ans[c[now-1]-'A']!=-1) { if((ans[a[now-1]-'A']+ans[b[now-1]-'A'])%n==ans[c[now-1]-'A']) flag=0; else if((ans[a[now-1]-'A']+ans[b[now-1]-'A']+1)%n==ans[c[now-1]-'A']) flag=1; else return; } for(int i=now-2;i>=0;i--) { if(ans[a[i]-'A']!=-1 && ans[b[i]-'A']!=-1 && ans[c[i]-'A']!=-1) if((ans[a[i]-'A']+ans[b[i]-'A'])%n!=ans[c[i]-'A'] && (ans[a[i]-'A']+ans[b[i]-'A']+1)%n!=ans[c[i]-'A']) return; } int & aa=ans[a[now]-'A'],& bb=ans[b[now]-'A'],& cc=ans[c[now]-'A']; if(aa!=-1 && bb!=-1 && cc!=-1) { if((aa+bb+bit[now])%n==cc) { bit[now-1]=(aa+bb+bit[now])/n; if(flag!=2 && bit[now-1]!=flag) return; dfs(now-1); if(ok) return; } else return; } else if(aa!=-1 && bb!=-1) { if(use[(aa+bb+bit[now])%n]) return; bit[now-1]=(aa+bb+bit[now])/n; if(flag!=2 && bit[now-1]!=flag) return; cc=(aa+bb+bit[now])%n; use[cc]=true; dfs(now-1); if(ok) return; use[cc]=false; cc=-1; } else if(aa!=-1 && cc!=-1) { if(aa+bit[now]<=cc) { if(use[cc-aa-bit[now]]) return; bit[now-1]=0; if(flag!=2 && bit[now-1]!=flag) return; bb=cc-aa-bit[now]; use[bb]=true; dfs(now-1); if(ok) return; } else { if(use[cc+n-aa-bit[now]]) return; bit[now-1]=true; if(flag!=2 && bit[now-1]!=flag) return; bb=(cc+n-aa-bit[now])%n; use[bb]=true; dfs(now-1); if(ok) return; } use[bb]=false; bb=-1; } else if(bb!=-1 && cc!=-1) { if(bb+bit[now]<=cc) { if(use[cc-bb-bit[now]]) return; bit[now-1]=0; if(flag!=2 && bit[now-1]!=flag) return; aa=cc-bb-bit[now]; use[aa]=true; dfs(now-1); if(ok) return; } else { if(use[cc+n-bb-bit[now]]) return; bit[now-1]=true; if(flag!=2 && bit[now-1]!=flag) return; aa=(cc+n-bb-bit[now])%n; use[aa]=true; dfs(now-1); if(ok) return; } use[aa]=false; aa=-1; } else if(aa!=-1) { for(int i=n-1;i>=0;i--) { if(use[i]) continue; if(use[(aa+i+bit[now])%n]) continue; bit[now-1]=(aa+i+bit[now])/n; if(flag!=2 && bit[now-1]!=flag) return; bb=i; cc=(aa+i+bit[now])%n; use[bb]=use[cc]=true; dfs(now-1); if(ok) return; use[bb]=use[cc]=false; bb=cc=-1; } } else if(bb!=-1) { for(int i=n-1;i>=0;i--) { if(use[i]) continue; if(use[(bb+i+bit[now])%n]) continue; bit[now-1]=(i+bb+bit[now])/n; if(flag!=2 && bit[now-1]!=flag) return; aa=i; cc=(bb+i+bit[now])%n; use[aa]=use[cc]=true; dfs(now-1); if(ok) return; use[aa]=use[cc]=false; aa=cc=-1; } } else if(cc!=-1) { for(int i=n-1;i>=0;i--) { if(use[i]) continue; if(i+bit[now]<=cc && !use[cc-i-bit[now]]) { bit[now-1]=0; if(flag!=2 && bit[now-1]!=flag) return; aa=i; bb=cc-i-bit[now]; use[aa]=use[bb]=true; dfs(now-1); if(ok) return; use[aa]=use[bb]=false; aa=bb=-1; } else if(i+bit[now]>cc && !use[cc+n-i-bit[now]]) { bit[now-1]=1; if(flag!=2 && bit[now-1]!=flag) return; aa=i; bb=(cc+n-i-bit[now])%n; use[aa]=use[bb]=true; dfs(now-1); if(ok) return; use[aa]=use[bb]=false; aa=bb=-1; } } } else { for(int i=n-1;i>=0;i--) { if(use[i]) continue; for(int j=n-1;j>=0;j--) { if((a[now]!=b[now] && i==j) || (a[now]==b[now] && i!=j) || use[j] || use[(i+j+bit[now])%n]) continue; bit[now-1]=(i+j+bit[now])/n; if(flag!=2 && bit[now-1]!=flag) return; aa=i; bb=j; cc=(i+j+bit[now])%n; use[aa]=use[bb]=use[cc]=true; dfs(now-1); if(ok) return; use[aa]=use[bb]=use[cc]=false; aa=bb=cc=-1; } } } } int main() { scanf("%d%s%s%s",&n,a,b,c); memset(ans,-1,sizeof(ans)); dfs(n-1); }