Cho phương trình: các từ bên trái cộng nhau = từ kết quả bên phải. Kiểm tra có giải được không với quy tắc: mỗi ký tự ánh xạ 1 chữ số (0-9), ký tự khác nhau → chữ số khác nhau, không số dẫn đầu 0, tổng bên trái = bên phải.
Ví dụ: words=["SEND","MORE"], result="MONEY" → True. Ánh xạ: S→9, E→5, N→6, D→7, M→1, O→0, R→8, Y→2. Khi đó 9567+1085=10652.
Giải pháp
Backtracking cột theo cột (từ phải sang trái) với carry:
- Đảo ngược tất cả từ và result
- Mảng i2c[10]: chữ số → ký tự, c2i[26]: ký tự → chữ số (-1 nếu chưa gán)
- Hàm solve(idx, l, sum): xử lý cột l, từ idx, carry = sum
- Nếu l == result.length(): trả về sum == 0
- Nếu idx == words.size(): xử lý chữ số kết quả tại cột l
- Nếu l ≥ words[idx].length(): chuyển từ tiếp theo
- Nếu ký tự đã gán: kiểm tra leading zero, cộng vào sum, đệ quy
- Nếu chưa gán: thử mọi chữ số 0-9 chưa dùng, kiểm tra leading zero, gán, đệ quy, backtrack
Ví dụ mã C++
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
char i2c[10];
int c2i[26];
vector<string> w;
string r;
bool solve(int idx, int l, int sum) {
if (l == r.size()) return sum == 0;
if (idx == w.size()) {
if (c2i[r[l] - 'A'] != -1) {
if (c2i[r[l] - 'A'] == sum % 10)
return solve(0, l + 1, sum / 10);
} else if (i2c[sum % 10] == -1) {
if (l == r.size() - 1 && sum % 10 == 0) return false;
c2i[r[l] - 'A'] = sum % 10;
i2c[sum % 10] = r[l] - 'A';
bool temp = solve(0, l + 1, sum / 10);
c2i[r[l] - 'A'] = -1;
i2c[sum % 10] = -1;
return temp;
}
return false;
}
if (l >= w[idx].size()) return solve(idx + 1, l, sum);
if (c2i[w[idx][l] - 'A'] != -1) {
if (l == w[idx].size() - 1 && c2i[w[idx][l] - 'A'] == 0) return false;
return solve(idx + 1, l, sum + c2i[w[idx][l] - 'A']);
}
for (int i = 0; i < 10; i++) {
if (i2c[i] != -1) continue;
if (i == 0 && l == w[idx].size() - 1) continue;
i2c[i] = w[idx][l] - 'A';
c2i[w[idx][l] - 'A'] = i;
bool temp = solve(idx + 1, l, sum + i);
i2c[i] = -1;
c2i[w[idx][l] - 'A'] = -1;
if (temp) return true;
}
return false;
}
bool isSolvable(vector<string>& words, string result) {
memset(i2c, -1, sizeof(i2c));
memset(c2i, -1, sizeof(c2i));
reverse(result.begin(), result.end());
for (int i = 0; i < words.size(); i++) {
if (words[i].size() > result.size()) return false;
reverse(words[i].begin(), words[i].end());
}
r = result;
w = words;
return solve(0, 0, 0);
}
};
int main() {
Solution ob;
vector<string> v = {"SEND","MORE"};
cout << (ob.isSolvable(v, "MONEY"));
return 0;
}
Đầu vào
{"SEND","MORE"}, "MONEY"
Đầu ra
1