版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84144206
思路分析:
从相加的最低两位开始考察, 注意利用已知两个数可求第三个数进行剪枝. 注意在下面的AC代码中第59, 68和77行的i值如果从0开始递增会TLE, 显然这与测试用例有关系!!!
//CH2902_虫食算
#include <iostream>
#include <cstring>
using namespace std;
char s1[30], s2[30], s3[30]; int N;
//val['A']为A对应数字, 未确定时val['A'] < 0, ok的第0位为1表示'A'对应数字已经确定
//used[i]为1表示值i对应字母已经确定, 为0表示未确定
int val[200], ok, used[30];
//将num填到空格val[ch], 并更新ok, used
void fill(int ch, int num){
val[ch] = num, ok ^= 1 << num, used[num] = 1;
}
//如果当前方案成立, 返回true, 不成立返回false
bool check(){
for(int i = N, ca = 0; i >= 1; --i){
int s = val[s1[i]] + val[s2[i]] + ca;
if(s >= N) s %= N, ca = 1; else ca = 0;
if(s != val[s3[i]]) return false;
}
return true;
}
//now当前正在考察的算式的列(最低位对应第0列), ca第now + 1列的进位值
void dfs(int now, int ca){
if(ok == (1 << N) - 1) return;
int a = s1[now], b = s2[now], c = s3[now];
//如果a, b, c对应值均已确定
if(val[a] >= 0 && val[b] >= 0 && val[c] >= 0){
if(!(val[a] + val[b] + ca == val[c] || val[a] + val[b] + ca == N + val[c])) return;
dfs(now - 1, (val[a] + val[b] + ca) / N); return;
}
//当前计算结果剪枝, 已知两个加数的值
if(val[a] >= 0 && val[b] >= 0){
int sum = val[a] + val[b] + ca, tca = sum >= N? 1: 0; sum %= N;
if(used[sum]) return;
fill(c, sum), dfs(now - 1, tca); return;
}
//已知一个加数与和的值
if(val[a] >= 0 && val[c] >= 0){
if(val[c] >= val[a] + ca){
int tb = val[c] - val[a] - ca; if(used[tb]) return;
fill(b, tb), dfs(now - 1, 0); return;
}
int tb = val[c] + N - val[a] - ca; if(used[tb]) return;
fill(b, tb), dfs(now - 1, 1); return;
}
if(val[b] >= 0 && val[c] >= 0){
if(val[c] >= val[b] + ca){
int ta = val[c] - val[b] - ca; if(used[ta]) return;
fill(a, ta), dfs(now - 1, 0); return;
}
int ta = val[c] + N - val[b] - ca; if(used[ta]) return;
fill(a, ta), dfs(now - 1, 1); return;
}
//至此说明当前第now列至少有两个值尚未确定
int arrv[50], tok, arru[30];
memcpy(arrv + 1, val + 'A', sizeof(int) * N), memcpy(arru, used, sizeof(int) * N), tok = ok;
//a未确定
if(val[a] < 0){
for(int i = N; i >= 0; --i)
if(!used[i]){
fill(a, i), dfs(now, ca);
if(ok == (1 << N) - 1 && check()) return;
else memcpy(val + 'A', arrv + 1, sizeof(int) * N), memcpy(used, arru, sizeof(int) * N), ok = tok;
}
return;
}
if(val[b] < 0){
for(int i = N; i >= 0; --i)
if(!used[i]){
fill(b, i), dfs(now, ca);
if(ok == (1 << N) - 1 && check()) return;
else memcpy(val + 'A', arrv + 1, sizeof(int) * N), memcpy(used, arru, sizeof(int) * N), ok = tok;
}
return;
}
if(val[c] < 0)
for(int i = N; i >= 0; --i)
if(!used[i]){
fill(c, i), dfs(now, ca);
if(ok == (1 << N) - 1 && check()) return;
else memcpy(val + 'A', arrv + 1, sizeof(int) * N), memcpy(used, arru, sizeof(int) * N), ok = tok;
}
}
int main(){
cin >> N >> s1 + 1 >> s2 + 1 >> s3 + 1;
memset(val, 0xff, sizeof(val));
dfs(N, 0);
for(int i = 'A'; i <= 'A' + N - 1; ++i) cout << val[i] << " ";
}