公式

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)

投稿日時:
最終更新: