心累,,、数独那道题太搞人了,硬是要二进制优化才能过……
相比之下这道题简单多了
主要思路:
- 先记录有多少个未知字母
- 按照从个位到高位,从被减数、减数、差的顺序去枚举
- 然后是按照得到的字母顺序去从0~n猜哪个字母是哪个数字
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 100;
int tot, n, num[N], used[N], vis[N];
char s[4][N], ch[N];
bool ck() {
int x = 0;
for(int i = n; i >= 1; i --) {
int a = num[s[1][i] - 'A'],
b = num[s[2][i] - 'A'],
c = num[s[3][i] - 'A'];
if(a != -1 && b != -1 && c != -1) {//某一列竖式上的三个数都确定了
if(x != -1) {//能确定进位
if((a + b + x) % n != c) return 0;//不匹配
if(i == 1 && a + b + x >= n) return 0;//最高位还有进位?pass!
x = (a + b + x) / n;
}
else {//不完全知道,只能去猜
if((a + b) % n != c && (a + b + 1) % n != c)//进位只可能是0或1, 若两种可能都不满足就舍弃。
return 0;
if(i == 1 && a + b >= n)//最高位还有进位,舍弃。
return 0;
}
}
else x = -1;
}
return 1;
}
bool dfs(int x) {
if(x == tot + 1) return 1;
for(int i = 0; i < n; i ++)//n进制猜数
if(!used[i]) {
num[ch[x] - 'A'] = i;
used[i] = 1;
if(ck() && dfs(x + 1)) return 1;//没问题就会一直返回。
num[ch[x] - 'A'] = -1;
used[i] = 0;
}
return 0;
}
int main() {
memset(num, -1, sizeof num);
scanf("%d", &n);
for(int i = 1; i <= 3; i ++)
scanf("%s", s[i] + 1);
for(int j = n; j >= 1; j --)//这里有个小小的顺序:先将个位上的字母进队。
for(int i = 1; i <= 3; i ++)
if(!vis[s[i][j] - 'A']) {
vis[s[i][j] - 'A'] = true;
ch[++ tot] = s[i][j];//ch数组记录有多少种不同的字母
}
dfs(1);
for(int i = 0; i < n; i ++)
printf("%d ",num[i]);
puts("");
return 0;
}