公式
D - 共通巡回記録 / Common Tour Record 解説
by
D - 共通巡回記録 / Common Tour Record 解説
by
kyopro_friends
この問題はやや複雑なDFSの実装の練習問題です。
作られる巡回記録は、再帰的に
「a + (子で作られる巡回記録を任意の順序で連結したもの) + b」となります。
よって、DFSにより「この部分木により作られる巡回記録」の集合を求めれながら子の結果をマージしていけばよいです。
DFSの行きがけ順として作られる順列は一意であることから、子の訪問順序の決め方は全体高々 \((N-1)!\) 通りであることがわかり、巡回記録も高々 \((N-1)!\) 通りです。
また、自然な実装では、子の結果を連結する方法と、部分木の訪問順序を決める方法が1対1に対応するので、文字列の連結などにかかる時間も考慮して、全体で \(O((N-1)!*\log(N-1)!*N)=O(NN!\log N)\) となります。
実装例 (C++)
#include<bits/stdc++.h>
using namespace std;
int n;
vector<vector<int>> G;
set<string> dfs(int v, int pre){
// 子で作られる巡回記録を求める
vector<set<string>> child_set;
for(auto vv: G[v]){
if(vv == pre){
continue;
}
child_set.push_back(dfs(vv, v));
}
int k = child_set.size();
vector<int> idx(k);
for(int i=0; i<k; i++) idx[i] = i;
set<string> ans;
// 子の訪問順序を全て試す
do{
// 各子の巡回記録を全て試す
set<string> temp({""});
for(int i=0; i<k; i++){
set<string> temp2;
for(auto s: temp){
for(auto t: child_set[idx[i]]){
temp2.insert(s+t);
}
}
swap(temp, temp2);
}
// 子の巡回記録を連結した文字列の前後に a,b をつける
for(auto s: temp){
ans.insert("a" + s + "b");
}
}while(next_permutation(idx.begin(), idx.end()));
return ans;
}
set<string> solve(){
G = vector<vector<int>>(n);
for(int i=0; i<n-1; i++){
int x, y;
cin >> x >> y;
x--, y--;
G[x].push_back(y);
G[y].push_back(x);
}
return dfs(0, -1);
}
int main(){
cin >> n;
set<string> s = solve();
set<string> t = solve();
set<string> ans;
set_intersection(s.begin(), s.end(), t.begin(), t.end(), inserter(ans, ans.end()));
cout << ans.size() << endl;
for(auto s: ans){
cout << s << endl;
}
}
実装例 (Python)
import itertools
N = int(input())
G = []
def dfs(v, pre):
child_set = []
for vv in G[v]:
if vv == pre:
continue
child_set.append(dfs(vv, v))
ans = set()
for perm in itertools.permutations(child_set):
for ss in itertools.product(*perm):
ans.add("a" + "".join(ss) + "b")
return ans
def solve():
global G
G = [[] for _ in range(N)]
for i in range(N-1):
x, y = map(int, input().split())
x -= 1
y -= 1
G[x].append(y)
G[y].append(x)
return dfs(0, -1)
S = solve()
T = solve()
ans = sorted(S & T)
print(len(ans))
for s in ans:
print(s)
投稿日時:
最終更新:
