题目:
虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:
43#9865#045
+ 8468#6633
= 44445506678
其中#号代表被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5。
现在,我们对问题做两个限制:
首先,我们只考虑加法的虫食算。这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0。
其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。如果这个算式是N进制的,我们就取英文字母表午的前N个大写字母来表示这个算式中的0到N-1这N个不同的数字:但是这N个字母并不一定顺序地代表0到N-1)。输入数据保证N个字母分别至少出现一次。
BADC
+ CRDA
= DCCC
上面的算式是一个4进制的算式。很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。你的任务是,对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解。
如:
5
ABCED BDACE EBBAA
ABCDE都是相同的数,ABCED+BDACE=EBBAA,求它的A,B,C,D,E的数值。
思路:可不可以一步一步枚举,A=1到10,B=1到10......是可以但是(忘给了一个条件n<27)
。。。。。。无语恶心吧
我们也可以dfs一下,一步一步进行除,但是(n<27)
。。。。。。
我们也可以对dfs进行优化,两步两步除,但是(n<27)
。。。。。。
只能三步三步除了。。。。。。
先是读入(建议用二维数组,方便一点)
void read() { scanf("%d",&n); for (int i=0; i<3; i++){//总共有三行数。。。 while (ch<'A' || ch>'Z') ch=getchar(); for (int j=1; j<=n; j++) a[i][j]=ch-'A',ch=getchar(); } }
接下来我来解释一下我的个个变量的意义:
int f[30];//他算出来的数值 int a[3][30];//读入的ABCDE...... int g[30];//判断其是否计算过 int jw[30];//计算储存数值 int n;//读入的个数 bool ok=0;//判断是否输出 char ch;//用在快读中
这样就可以进行递推啦!(dfs(0,n))
if (x<2){//当x=0,或x=1时 int k=1-x; if (!f[a[x][y]]){//判断是否用过 if (f[a[k][y]] && f[a[2][y]]){//如果俩都用过 if (!g[(f[a[2][y]]-f[a[k][y]]-jw[y+1]+n)%n]){//判断是否计算过 f[a[x][y]]=(f[a[2][y]]-f[a[k][y]]-jw[y+1]+n)%n+1; g[f[a[x][y]]-1]=1; dfs(x+1,y);//递推下一位 if (ok) return;//如果已经输出了,跳出dfs g[f[a[x][y]]-1]=0;//回溯一步 f[a[x][y]]=0;//同上 } return;//跳出循环 } for (int i=n-1; i>=0; i--) if (!g[i]){//判断 f[a[x][y]]=i+1; g[f[a[x][y]]-1]=1; dfs(x+1,y); g[f[a[x][y]]-1]=0; f[a[x][y]]=0; } return; } dfs(x+1,y);//dfs一下 return; }
if (x==2){//和上面的差不多,稍作修改 if (!f[a[x][y]]){ f[a[x][y]]=(f[a[0][y]]-1+f[a[1][y]]-1+jw[y+1])%n+1; if (!g[f[a[x][y]]-1]){ g[f[a[x][y]]-1]=1; jw[y]=(jw[y+1]+f[a[0][y]]-1+f[a[1][y]]-1)/n; dfs(0,y-1); g[f[a[x][y]]-1]=0; } f[a[x][y]]=0; return; } if ((f[a[0][y]]-1+f[a[1][y]]-1+jw[y+1])%n==f[a[2][y]]-1){//判断 jw[y]=(jw[y+1]+f[a[0][y]]-1+f[a[1][y]]-1)/n; dfs(0,y-1); } return; }
下面是输出
if (y==0){//如果算完了 if (f[a[0][1]]-1+f[a[1][1]]-1+jw[2]==f[a[2][1]]-1){//如果满足条件 for (int i=0; i<n-1; i++) printf("%d ",f[i]-1); printf("%d",f[n-1]-1); ok=1;//让下面一直跳出循环 } return;//return掉 }
这样基本上就完事了
下面是代码(不是伪的)
#include<bits/stdc++.h> int f[30]; int a[3][30]; int g[30]; int jw[30]; int n; int ok; char ch; void dfs(int x,int y){ if (ok) return; if (y==0){ if (f[a[0][1]]-1+f[a[1][1]]-1+jw[2]==f[a[2][1]]-1){ for (int i=0; i<n-1; i++) printf("%d ",f[i]-1); printf("%d",f[n-1]-1); ok=1; } return; } if (x<2){ int k=1-x; if (!f[a[x][y]]){ if (f[a[k][y]] && f[a[2][y]]){ if (!g[(f[a[2][y]]-f[a[k][y]]-jw[y+1]+n)%n]){ f[a[x][y]]=(f[a[2][y]]-f[a[k][y]]-jw[y+1]+n)%n+1; g[f[a[x][y]]-1]=1; dfs(x+1,y); if (ok) return; g[f[a[x][y]]-1]=0; f[a[x][y]]=0; } return; } for (int i=n-1; i>=0; i--) if (!g[i]){ f[a[x][y]]=i+1; g[f[a[x][y]]-1]=1; dfs(x+1,y); g[f[a[x][y]]-1]=0; f[a[x][y]]=0; } return; } dfs(x+1,y); return; } if (x==2){ if (!f[a[x][y]]){ f[a[x][y]]=(f[a[0][y]]-1+f[a[1][y]]-1+jw[y+1])%n+1; if (!g[f[a[x][y]]-1]){ g[f[a[x][y]]-1]=1; jw[y]=(jw[y+1]+f[a[0][y]]-1+f[a[1][y]]-1)/n; dfs(0,y-1); g[f[a[x][y]]-1]=0; } f[a[x][y]]=0; return; } if ((f[a[0][y]]-1+f[a[1][y]]-1+jw[y+1])%n==f[a[2][y]]-1){ jw[y]=(jw[y+1]+f[a[0][y]]-1+f[a[1][y]]-1)/n; dfs(0,y-1); } return; } } void read() { scanf("%d",&n); for (int i=0; i<3; i++){ while (ch<'A' || ch>'Z') ch=getchar(); for (int j=1; j<=n; j++) a[i][j]=ch-'A',ch=getchar(); } } int main(){ read(); dfs(0,n); return 0; }
我这样的算法并不是最好的但是还可以,还可以四步四步算,五步五步算......但是有一种更好的方法——高斯消元,不会,所以没打。
谢谢!