就是给一个由字母组成的加法等式,问这个等式有多少种情况,相同字母代表相同数字,不同字母代表不同数字,不存在前导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; }