题目:
虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:
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;
}
我这样的算法并不是最好的但是还可以,还可以四步四步算,五步五步算......但是有一种更好的方法——高斯消元,不会,所以没打。
谢谢!