退役题解
同时致敬我的第一篇题解
这是一道搜索题
依次枚举每一个字母的值
然后要从低位开始搜
提前算进位
更多解释看代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
bool flag[95];
char a[28],b[28],c[28],d[28];
int v[95],n,tot;
inline void ycl() {//预处理,从低位到高位统计,以免重复计算进位
for(int i=n-1;i>=0;i--) {
if(!flag[a[i]]) {//每一个字母只统计一次
flag[a[i]]=1;
d[++tot]=a[i];//最先的肯定是最低位
}
if(!flag[b[i]]) {
flag[b[i]]=1;
d[++tot]=b[i];
}
if(!flag[c[i]]) {
flag[c[i]]=1;
d[++tot]=c[i];
}
}
memset(flag,0,sizeof(flag));
memset(v,-1,sizeof(v));//一定有一个字母为0,清为-1
}
inline bool check() {
for(int i=n-1;i>=0;i--) {//从低位到高位每一位都要check
if(v[a[i]]!=-1&&v[b[i]]!=-1&&v[c[i]]!=-1) {//三个数字都知道
if((v[a[i]]+v[b[i]])%n!=v[c[i]]&&(v[a[i]]+v[b[i]]+1)%n!=v[c[i]])//a[i]+b[i]正好是c[i]或进了一位
return 0;
}
else if(v[a[i]]!=-1&&v[b[i]]!=-1&&v[c[i]]==-1) {//下面三个都是确定两个之后剩下的一个就只有两种可能(正好或进(退)位)
if(flag[(v[a[i]]+v[b[i]])%n]&&flag[(v[a[i]]+v[b[i]]+1)%n])//如果这个两个可能的数都被用过,肯定不是正解
return 0;
}
else if(v[a[i]]!=-1&&v[b[i]]==-1&&v[c[i]]!=-1) {
if(flag[(v[c[i]]-v[a[i]]+n)%n]&&flag[(v[c[i]]-v[a[i]]-1+n)%n])
return 0;
}
else if(v[a[i]]==-1&&v[b[i]]!=-1&&v[c[i]]!=-1) {
if(flag[(v[c[i]]-v[b[i]]+n)%n]&&flag[(v[c[i]]-v[b[i]]-1+n)%n])
return 0;
}
}
return 1;
}
inline bool ok() {//从低位到高位依次比对
int jw=0;//进位
for(int i=n-1;i>=0;i--) {
if((v[a[i]]+v[b[i]]+jw)%n!=v[c[i]])//结果不等
return 0;//肯定不对
jw=(v[a[i]]+v[b[i]]+jw)/n;//计算有没有进位
}
if(jw)//如果计算完了仍然有进位,肯定是错的
return 0;
return 1;
}
inline void pr() {
for(int i='A';i<='A'-1+n;i++)//v[i]就是i这个字母所代表的值
if(v[i]!=-1)
printf("%d ",v[i]);
exit(0);//直接结束全部程序
}
void dfs(int x) {
if(x>n) {//所有位数都已确定
if(ok()) {//计算正确
pr();//输出答案
}
return;//不管怎样都要返回
}
for(int i=n-1;i>=0;i--) {
if(flag[i])//i这个值被用过
continue;
v[d[x]]=i;//将字母d[x]的值设定为i
flag[i]=1;//i已被用过
if(!check()) {//已经不成立
v[d[x]]=-1;
flag[i]=0;
continue;//回溯
}
dfs(x+1);//继续搜
v[d[x]]=-1;//回溯
flag[i]=0;
}
}
int main() {
scanf("%d%s%s%s",&n,a,b,c);
ycl();
dfs(1);
}