AtCoder Beginner Contest 031 D - 語呂合わせ
解法
n 番目の v, w の対応では各数字がどのような文字列に対応しているか, というのを深さ優先探索すれば OK です。
具体的な実装は, dfs(m, num, cur, S) = 「n 番目の v, w の対応を調べているが, v の方は num 番目の数字を, w の方は cur 番目以降の文字列を見ていて, 今までに数字と文字列の対応が決定したのは S で表される」という場合に相当します。
dfs でやるべきことは, v[n][num] に対応する文字列が w の cur からいくつの文字を取ったものになるのかを調べることです。
今までに v[n][num] = p という数に対応した文字列 S[p] がある場合は, w の cur からの文字列は S[p] に一致していなければならないことに注意して, 枝刈りをします。
このようにすると, 各文字が取りうる文字数である 3^9 しか場合分けが生じないので時間に間に合いそうです。
const int MAXN = 55; string v[MAXN], w[MAXN]; int K, N; // n 個目, 数字は num 番目, 文字は cur 番目 void dfs(int n, int num, int cur, vector<string>& S) { if (n == N) { for (int i = 0; i < N; i++) { string s; for (char c : v[i]) { s += S[c-'0']; } if (s != w[i]) return; } for (string s : S) cout << s << endl; exit(0); } for (int i = 1; i <= 3; i++) { if (cur+i > w[n].size()) continue; int p = v[n][num] - '0'; string s = w[n].substr(cur, i); if (!S[p].empty() && S[p] != s) continue; string old = S[p]; if (num+1 == v[n].size()) { if (cur+i != w[n].size()) continue; S[p] = s; dfs(n+1, 0, 0, S); } else { S[p] = s; dfs(n, num+1, cur+i, S); } S[p] = old; } } int main() { cin.tie(0); ios::sync_with_stdio(false); cin >> K >> N; for (int i = 0; i < N; i++) { cin >> v[i] >> w[i]; } for (int i = 0; i < N; i++) { for (char& c : v[i]) c--; } vector<string> s; s.resize(K); dfs(0, 0, 0, s); return 0; }