就是给一个由字母组成的加法等式,问这个等式有多少种情况,相同字母代表相同数字,不同字母代表不同数字,不存在前导0.
呃,就是DFS搜索,但是刚开始我的姿势不对,就T了。
刚开始我是就枚举前面的所有情况,然后看得到的和能不能组成最后的和。然后,这个搜索姿势很智障地T了。。。
然后就去度娘了,,,发现要按每一位进行搜索,就是搜索所有的个位数,然后查看和的个位数是否能满足,再依次搜索十位,百位。。
这样,如果不合法,就可以很早地发现,算是一个很大的剪枝了。。
最后因为最后一个数字的长度太长和太短而错了几发,,就这样了。。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
char formu[12][12];
int idx[27];
int n, llen, maxlen;
bool nozero[27];
bool num[10];
int DFS(int x, int y, int carry)
{
int ans = 0;
if (x == n - 1)
{
int sum = 0;
bool new_num = 0;
for (int i = 0; i < n - 1; ++i)
sum += idx[formu[i][y]];
sum += carry;
int last = sum % 10;
if (idx[formu[x][y]] == -1)
{
if (num[last]||(last==0&&nozero[formu[x][y]]))
{
return 0;
}
new_num = 1;
idx[formu[x][y]] = last;
num[last] = 1;
}
else if (last != idx[formu[x][y]])
{
return 0;
}
if (y == llen - 1 && sum / 10 == 0)
{
ans = 1;
if (new_num)
{
idx[formu[x][y]] = -1;
num[last] = 0;
}
}
else
{
ans = DFS(0, y + 1, sum / 10);
if (new_num)
{
idx[formu[x][y]] = -1;
num[last] = 0;
}
}
}
else if (idx[formu[x][y]] == -1)
{
int i = 0;
if (nozero[formu[x][y]])
i = 1;
for (; i <= 9; ++i)
{
if (num[i])
continue;
idx[formu[x][y]] = i;
num[i] = 1;
ans += DFS(x + 1, y, carry);
num[i] = 0;
}
idx[formu[x][y]] = -1;
}
else
ans = DFS(x + 1, y, carry);
return ans;
}
int main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
while (scanf("%d", &n) != EOF)
{
memset(num, 0, sizeof(bool) * 10);
memset(formu, 0, sizeof(char) * 12 * 12);
memset(idx, -1, sizeof(int) * 27);
memset(nozero, 0, sizeof(bool) * 27);
idx[0] = 0, maxlen = 0;
int ans = 0;
for (int i = 0; i < n; ++i)
{
scanf("%s", formu[i]);
int len = strlen(formu[i]);
if (len > maxlen)
maxlen = len;
for (int j = 0; j < (len + 1) / 2; ++j)
{
char tmp = formu[i][j] - 'A' + 1;
formu[i][j] = formu[i][len - 1 - j] - 'A' + 1;
formu[i][len - 1 - j] = tmp;
}
nozero[formu[i][len - 1]] = 1;
}
llen = strlen(formu[n - 1]);
if (maxlen==llen)
ans = DFS(0, 0, 0);
printf("%d\n", ans);
}
//system("pause");
//while (1);
return 0;
}