link
解题思路
40分:暴力搜索每个字母代表的数
考虑剪枝 (搜索字母的顺序按竖式的从右到左,方便剪枝)
每搜索一个字母时,其实已经可以判断竖式的可行性了
- 当竖式上当前位的右边都有时, ( x + y ) % n < > z (x+y)\%n<>z (x+y)%n<>z不可行(加数 x , y x,y x,y,和 z z z)。
但是还要考虑进位,设右边进位 t t t, ( x + y + t ) % n < > z (x+y+t)\%n<>z (x+y+t)%n<>z不可行 - 当竖式上当前位的右边有字母没有搜索时,无法判断有没有进位
但是加法中的进位最多为1,即当 ( x + y ) % n < > z (x+y)\%n<>z (x+y)%n<>z且 ( x + y + 1 ) % n < > z (x+y+1)\%n<>z (x+y+1)%n<>z不可行 - 当前位已是第一位,但是依然有进位, ( i = = 1 ) (i ==1) (i==1)且 ( x + y ) / n > 0 (x+y)/n>0 (x+y)/n>0不可行
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
using namespace std;
string s[5];
int n, ans[30], v[30], q[30], num, h;
bool check() {
//判断可行性
int t = 0;
for (int i = n; i; i--) {
int x = ans[s[1][i - 1] - 'A' + 1], y = ans[s[2][i - 1] - 'A' + 1], z = ans[s[3][i - 1] - 'A' + 1];
if (x != -1 && y != -1 && z != -1) {
if (t != -1) {
if ((x + y + t) % n != z) return 0;//1
if (i == 1 && (x + y + t) / n) return 0;//3
t = (x + y + t) / n;
}else {
if ((x + y) % n != z && (x + y + 1) % n != z) return 0;//2
if (i == 1 && (x + y) / n) return 0;//3
}
}else t = -1;//当前位有字母还没搜索,进位设为-1
}
return 1;
}
void dfs(int x) {
if (h) return;//已经找到答案就直接返回
if (x > n) {
//找到答案
for (int i = 1; i <= n; i++)
printf ("%d ", ans[i]);
h = 1;
return;
}
for (int i = 0; i < n; i++) {
if (!v[i]) {
//搜索每个字母可用数字
v[i] = 1, ans[q[x]] = i;
if (check())
dfs(x + 1);
v[i] = 0, ans[q[x]] = -1;
}
}
}
int main() {
scanf("%d", &n);
cin>>s[1]>>s[2]>>s[3];
for (int i = n - 1; i >= 0; i--) //从有到左
for (int j = 1; j <= 3; j++) //从上到下(这个不太重要)
if (!v[s[j][i] - 'A' + 1]) {
v[s[j][i] - 'A' + 1] = 1;
q[++num] = s[j][i] - 'A' + 1;//字母按出现顺序记录
}
memset (v, 0, sizeof(v));
memset (ans, -1, sizeof(ans));
dfs(1);
}