>Link
ybtoj虫食算
>解题思路
30分做法:暴搜每个字母所代表的数字,然后判断是否合法
正解
我们可以考虑如下剪枝:
模拟加法的过程,记录当前位的加数 j 1 j1 j1、 j 2 j2 j2和和 p p p
- 如果当前位右边所有的数都确定了,那么也就可以确定进位为 g g g,如果 j 1 + j 2 + g ≠ p j1+j2+g≠p j1+j2+g=p的话,舍去
- 如果当前位右边有数没有确定的话,那么当前进位 g g g可能为1或者0,如果 j 1 + j 2 j1+j2 j1+j2 和 j 1 + j 2 + 1 j1+j2+1 j1+j2+1 均 ≠ p ≠p =p,也说明不合法
- 最后检查一下位数是否会大于 n n n
应用这个思想,我们搜索的时候也应该按照从右到左最先出现的字母开始搜
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n, w[30], q[30];
string s[5];
bool u[30], mark[30];
bool check ()
{
int g = 0, j1, j2, p;
for (int i = n; i >= 1; i--)
{
j1 = w[s[1][i - 1] - 'A' + 1];
j2 = w[s[2][i - 1] - 'A' + 1];
p = w[s[3][i - 1] - 'A' + 1];
if (j1 != -1 && j2 != -1 && p != -1)
{
if (g != -1)
{
if ((j1 + j2 + g) % n != p) return 0;
g = (j1 + j2 + g) / n;
}
else
{
if ((j1 + j2) % n != p && (j1 + j2 + 1) % n != p) return 0;
if (i == 1 && j1 + j2 >= n) return 0;
}
}
else g = -1;
}
if (g > 0) return 0;
return 1;
}
void dfs (int now)
{
if (now == n + 1)
{
for (int i = 1; i <= n; i++) printf ("%d ", w[i]);
exit (0); return;
}
for (int i = 0; i < n; i++)
if (!u[i])
{
w[q[now]] = i; u[i] = 1;
if (check ()) dfs (now + 1);
w[q[now]] = -1; u[i] = 0;
}
}
int main()
{
scanf ("%d", &n);
for (int i = 1; i <= n; i++) w[i] = -1;
for (int i = 1; i <= 3; i++) cin >> s[i];
for (int j = n; j >= 1; j--)
for (int i = 1; i <= 3; i++)
if (!mark[s[i][j - 1] - 'A' + 1])
mark[s[i][j - 1] - 'A' + 1] = 1, q[++q[0]] = s[i][j - 1] - 'A' + 1;
dfs (1);
return 0;
}