版权声明: https://blog.csdn.net/qq_38234381/article/details/82320193
题目链接:https://www.luogu.org/problemnew/show/P1092
正解是高斯消元,但搜索也勉强可以过。
首先一个很明显的思路就是竖着搜的策略,一旦发现不合法的情况,就return。但这样最多也只能得80分,因此需要剪枝,可以在每次搜索之前从当前位置到0进行一次判断,若有不合法的情况,就返回false,具体可以看代码。
code:
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=30;
int n, ans[N], cn[N], nc[N];
string s1, s2, s3;
bool finds;
bool check(int pos) {
int i, temp1, temp2, temp3, k;
for (i=pos; i>=0; i--) {
temp1=cn[s1[i]-'A'+1], temp2=cn[s2[i]-'A'+1], temp3=cn[s3[i]-'A'+1];
if (temp1==-1 || temp2==-1 || temp3==-1) continue;
if (temp1+temp2>=n-1) k=temp1+temp2-n;
else k=temp1+temp2;
if (k>temp3) return false;
if (k+1<temp3) return false;
}
return true;
}
void dfs(int pos, int last) {
int i, j, k;
if (!check(pos)) return ;
if (pos == -1) {
finds=true;
return ;
}
if (cn[s1[pos]-'A'+1]<0 && cn[s2[pos]-'A'+1]<0) {
if (s1[pos]!=s2[pos]) {
for (i=0; i<n; i++) {
if (nc[i]) continue;
for(j=0; j<n; j++) {
if (nc[j]) continue;
if (i==j) continue;
bool flag=false;
int carry=0;
cn[s1[pos]-'A'+1]=i, cn[s2[pos]-'A'+1]=j;
if (i+j+last>=n) {
k=i+j+last-n;
carry=1;
}
else k=i+j+last;
if (cn[s3[pos]-'A'+1]<0) {
flag=true;
cn[s3[pos]-'A'+1]=k;
}
else if (cn[s3[pos]-'A'+1]!=k) {
cn[s1[pos]-'A'+1]=-1, cn[s2[pos]-'A'+1]=-1;
continue;
}
nc[i]=s1[pos]-'A'+1, nc[j]=s2[pos]-'A'+1;
dfs(pos-1, carry);
if (finds) return ;
cn[s1[pos]-'A'+1]=-1, cn[s2[pos]-'A'+1]=-1;
nc[i]=0, nc[j]=0;
if (flag) cn[s3[pos]-'A'+1]=-1;
}
}
}
else {
for (i=0; i<n; i++) {
if (nc[i]) continue;
int carry=0;
bool flag=false;
cn[s1[pos]-'A'+1]=i, j=i;
if (i+j+last>=n) {
k=i+j+last-n;
carry=1;
}
else k=i+j+last;
if (cn[s3[pos]-'A'+1]<0) {
flag=true;
cn[s3[pos]-'A'+1]=k;
}
else if (cn[s3[pos]-'A'+1]!=k) {
cn[s1[pos]-'A'+1]=-1;
continue;
}
nc[i]=s1[pos]-'A'+1;
dfs(pos-1,carry);
if (finds) return ;
cn[s1[pos]-'A'+1]=-1, nc[i]=0;
if (flag) cn[s3[pos]-'A'+1]=-1;
}
}
}
else {
if (cn[s1[pos]-'A'+1]<0 && cn[s2[pos]-'A'+1]>=0) {
for (i=0; i<n; i++) {
if (nc[i]) continue;
int carry=0;
bool flag=false;
cn[s1[pos]-'A'+1]=i, j=cn[s2[pos]-'A'+1];
if(i+j+last>=n) {
k=i+j+last-n;
carry=1;
}
else k=i+j+last;
if (cn[s3[pos]-'A'+1]<0) {
flag=true;
cn[s3[pos]-'A'+1]=k;
}
else if (cn[s3[pos]-'A'+1]!=k) {
cn[s1[pos]-'A'+1]=-1;
continue;
}
nc[i]=s1[pos]-'A'+1;
dfs(pos-1, carry);
if (finds) return ;
cn[s1[pos]-'A'+1]=-1, nc[i]=0;
if (flag) cn[s3[pos]-'A'+1]=-1;
}
}
if (cn[s1[pos]-'A'+1]>=0 && cn[s2[pos]-'A'+1]<0) {
for (i=0; i<n; i++) {
if (nc[i]) continue;
int carry=0;
bool flag=false;
cn[s2[pos]-'A'+1]=i, j=cn[s1[pos]-'A'+1];
if(i+j+last>=n) {
k=i+j+last-n;
carry=1;
}
else k=i+j+last;
if (cn[s3[pos]-'A'+1]<0) {
flag=true;
cn[s3[pos]-'A'+1]=k;
}
else if (cn[s3[pos]-'A'+1]!=k) {
cn[s2[pos]-'A'+1]=-1;
continue;
}
nc[i]=s2[pos]-'A'+1;
dfs(pos-1, carry);
if (finds) return ;
cn[s2[pos]-'A'+1]=-1, nc[i]=0;
if (flag) cn[s3[pos]-'A'+1]=-1;
}
}
if (cn[s1[pos]-'A'+1]>=0 && cn[s2[pos]-'A'+1]>=0) {
int carry=0;
bool flag=false;
i=cn[s1[pos]-'A'+1], j=cn[s2[pos]-'A'+1];
if (i+j+last>=n) {
k=i+j+last-n;
carry=1;
}
else k=i+j+last;
if (cn[s3[pos]-'A'+1]<0) {
flag=true;
cn[s3[pos]-'A'+1]=k;
}
else if (cn[s3[pos]-'A'+1]!=k) return ;
dfs(pos-1, carry);
if (finds) return ;
if (flag) cn[s3[pos]-'A'+1]=-1;
}
}
return ;
}
int main() {
memset(cn, -1, sizeof(cn));
int i;
cin >> n;
cin >> s1 >> s2 >> s3;
dfs(n-1, 0);
for (i=1; i<=n; i++)
cout << cn[i] <<" ";
return 0;
}
如果不开O2的话只能得90分,剪枝和搜索的过程都比较玄学。