目录
1.题目描述
所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。
来看一个简单的例子:
43#9865#045
+ 8468#6633
--------------
44445506978
其中 #
号代表被虫子啃掉的数字。
根据算式,我们很容易判断:第一行的两个数字分别是 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 个不同的字母分别代表的数字,使得该加法算式成立。
输入数据保证有且仅有一组解。
输入格式
输入包含 4 行。
第一行有一个正整数 N(N≤26)),后面的 3 行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。
这 3 个字符串左右两端都没有空格,并且恰好有 N 位。
输出格式
输出包含一行。
在这一行中,应当包含唯一的那组解。
解是这样表示的:输出 N 个数字,分别表示 A,B,C……所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。
输入样例:
5
ABCED
BDACE
EBBAA
输出样例:
1 0 3 4 2
2.题意
题意:给你一个数字表示接下来的数字是几进制的数,再给你三行字符串表示两个数以及这两数相加的和,然后让你推测出,这些字符串中各个字符代表的数是多少,最后按字母A~Z的顺序输出对应字符代表的数。
3.解题思路
思路:先将由最后一列向第一列遍历,所遍历到的未存储过的字符先存储起来,然后通过DFS,每一步确定一个字符所对应的数字,每一步可以选择的数字为从0到n-1,如果选择当前字符再代入给出算式是合法的则可进入下一个字符的确定,否则返回,当全部的字符都确定,且合法后,DFS结束。
4.代码实现
str[3][]:存储输入的三行数字
n:表示进制数
q[]:存储由最后一列遍历到第一列先后n个不同的字符
path[]:存储这n个字符对应的数字
st[]:判断该数字是否使用过
代码思路:先将三个数当成字符串输入到str中,然后由最后一列开始,将每一个未存储的字符存入q[],然后初始化st[],和path[]。dfs(0),由第一个字符开始确定数字,可确定的数字由0枚举到n-1,如st[i]=false,则可以选择该数字,并将该数字加入到path[q[u]]中,然后判断这样赋值是否合法,若合法则dfs(t+1),进行下一个字符的确认。当全部字符确认后,dfs结束,输出path[]里,存储的各个字符对应的数字。
赋值是否合法,则由最后一列开始模拟第一行和第二行两数的计算,若每一列的模拟计算都正确,则合法,反之不合法。
#include<iostream>
#include<cstring>
using namespace std;
const int N = 30;
char str[3][N];
int n;
int q[N], path[N];
bool st[N];
bool check() {
for (int i = n - 1, t = 0; i >= 0; i--) {///由最后一列开始,模拟计算
int a = str[0][i] - 'A', b = str[1][i] - 'A', c = str[2][i] - 'A';
if (path[a] != -1 && path[b] != -1 && path[c] != -1) {///三个数都有赋值,则按式子计算
a = path[a], b = path[b], c = path[c];
if (t != -1) {///若前一列计算出的余数确定,则直接计算
/// 第一列的余数必须为零
if ((a + b + t) % n != c || (i == 0 && (a + b + t) / n > 0)) return false;
t = (a + b + t) / n;
}
else {///若前一列计算的余数不确定,则0,1都有可能,若两种带入式子都不行,则赋值错误
if ((a + b + 0) % n != c && (a + b + 1) % n != c) return false;
if (i == 0 && (a + b) / n > 0) return false;
}
}
else t = -1;///若三个字符不是都赋值,则该列计算的余数不清楚,则让余数t=-1
}
return true;
}
bool dfs(int u) {
if (u == n) return ;
for (int i = 0; i < n; i++) {
if (!st[i]) {///判断该数字是否被使用
st[i] = true;
path[q[u]] = i;///给当前的第u个字符附值
if (check() && dfs(u + 1)) return true;
st[i] = false;
path[q[u]] = -1;
}
}
return false;
}
int main() {
cin >> n;
cin >> str[0] >> str[1] >> str[2];
for (int i = n - 1, k = 0; i >= 0; i--) {
for (int j = 0; j < 3; j++) {
int t = str[j][i] - 'A';
if (!st[t]) {///判断该字符是否被存储过
st[t] = true;
q[k++] = t;
}
}
}
memset(st, false, sizeof st);
memset(path, -1, sizeof path);
dfs(0);
for (int i = 0; i < n; i++) cout << path[i] << ' ';
return 0;
}