yokobuttonの不定期で競技プログラミングをするブログ

不定期で解けた競技プログラミングコンテストの問題を載せています。

木の同型性判定プログラム

//木の同型性判定プログラム
//"Explanation for Tree isomorphism talk"と"木を隠すなら森の中"を参考にプログラミングしてみました。
//ソースコードC++
//入力:頂点数n、(辺数n-1)、の二つの根なし無向木T1とT2
//出力:T1とT2が同型ならば"Yes"、そうでないならば"No"

#include <iostream>
#include <vector>
#include <unordered_map>
#include <string>
#include <cmath>

using namespace std;

const long long null = -1;

//tree
typedef vector< vector< long long > > Tree;
long long n;
long long m;
Tree T1;
Tree T2;

//centers of tree
vector<long long> nums;
long long max_num;
long long farthest_path_num;
long long r;
long long T1_farthest_vertex_1;
long long T1_farthest_vertex_2;
long long T2_farthest_vertex_1;
long long T2_farthest_vertex_2;
long long T1_center_1;
long long T1_center_2;
long long T2_center_1;
long long T2_center_2;

//isomorphism
unordered_map<string, long long> T1_name_num_1;
unordered_map<string, long long> T1_name_num_2;
unordered_map<string, long long> T2_name_num_1;
unordered_map<string, long long> T2_name_num_2;
vector<long long> T1_names_1;
vector<long long> T1_names_2;
vector<long long> T2_names_1;
vector<long long> T2_names_2;
long long num;
const long long max_digit_num = 10;

void dfs1(Tree T, long long v, long long num){
    for(long long i = 0; i < T[v].size(); i++){
        long long w = T[v][i];
        if(nums[w] == null){
            nums[w] = num+1;
            dfs1(T, w, num+1);
        }
    }
    return;
}

void radix_sort(vector<long long> &sub_names){
    vector<vector<long long>> bucket(10);
    for(long long d = 0, r = 1; d < max_digit_num; d++, r *= 10){
        for(long long i = 0; i < sub_names.size(); i++){
            long long key = (sub_names[i] / r) % 10;
            bucket[key].push_back(sub_names[i]);
        }
        for(long long j = 0, i = 0; j < 10; j++){
            if(!bucket[j].empty()){
                for(long long k = 0; k < bucket[j].size(); k++){
                    sub_names[i++] = bucket[j][k];
                }
            }
        }
        for(long long i = 0; i < 10; i++){
            bucket[i].clear();
        }
    }

    return;
}

void dfs2(Tree T, unordered_map<string, long long> &name_num, vector<long long> &names, long long v, long long pre_v, long long level){
    if(T[v].size() == 0){
        if(name_num.count("0") == 0){
            num++;
            name_num.emplace("0", num);
        }
        names[v] = name_num["0"];
        return;
    }

    vector<long long> sub_names;
    for(long long i = 0; i < T[v].size(); i++){
        long long w = T[v][i];
        if(names[w] == 0 && w != pre_v){
            dfs2(T, name_num, names, w, v, level+1);
            sub_names.push_back(names[w]);
        }
    }
    radix_sort(sub_names);
    string name = "";
    for(long long i = 0; i < sub_names.size(); i++){
        name += to_string(sub_names[i]);
    }

    if(name_num.count(name) == 0){
        num++;
        name_num.emplace(name, num);
    }
    names[v] = name_num[name];

    return;
}

int main(){

    cin >> n;
    m = n-1;

    T1.resize(n);
    T2.resize(n);
    for(long long i = 0; i < m; i++){
        long long v,w;
        cin >> v >> w;
        T1[v].push_back(w);
        T1[w].push_back(v);
    }
    for(long long i = 0; i < m; i++){
        long long v,w;
        cin >> v >> w;
        T2[v].push_back(w);
        T2[w].push_back(v);
    }

    //centers of tree
    nums.resize(n, null);
    T1_farthest_vertex_1 = null;
    T1_farthest_vertex_2 = null;
    T2_farthest_vertex_1 = null;
    T2_farthest_vertex_2 = null;
    T1_center_1 = null;
    T1_center_2 = null;
    T2_center_1 = null;
    T2_center_2 = null;

    //T1_farthest_vertex_1を求める
    nums.assign(n, null);
    nums[0] = 0;
    dfs1(T1, 0, 0);
    max_num = 0;
    for(long long i = 0; i < n; i++){
        if(max_num < nums[i]){
            max_num = nums[i];
            T1_farthest_vertex_1 = i;
        }
    }

    //T1_farthest_vertex_2を求める
    nums.assign(n, null);
    nums[T1_farthest_vertex_1] = 0;
    dfs1(T1, T1_farthest_vertex_1, 0);
    max_num = 0;
    for(long long i = 0; i < n; i++){
        if(max_num < nums[i]){
            max_num = nums[i];
            T1_farthest_vertex_2 = i;
        }
    }

    farthest_path_num = max_num;
    r = ceil(double(farthest_path_num)/2.0);
    //cout << "T1-r ->" << r <<endl;

    //T1_center_1を求める
    nums.assign(n, null);
    nums[T1_farthest_vertex_1] = 0;
    dfs1(T1, T1_farthest_vertex_1, 0);
    for(long long i = 0; i < n; i++){
        if(nums[i] == r){
            T1_center_1 = i;
            break;
        }
    }

    //T1_center_2を求める
    nums.assign(n, null);
    nums[T1_farthest_vertex_2] = 0;
    dfs1(T1, T1_farthest_vertex_2, 0);
    for(long long i = 0; i < n; i++){
        if(nums[i] == r){
            T1_center_2 = i;
            break;
        }
    }

    //T2_farthest_vertex_1を求める
    nums[0] = 0;
    nums.assign(n, null);
    dfs1(T2, 0, 0);
    max_num = 0;
    for(long long i = 0; i < n; i++){
        if(max_num < nums[i]){
            max_num = nums[i];
            T2_farthest_vertex_1 = i;
        }
    }

    //T2_farthest_vertex_2を求める
    nums.assign(n, null);
    nums[T2_farthest_vertex_1] = 0;
    dfs1(T2, T2_farthest_vertex_1, 0);
    max_num = 0;
    for(long long i = 0; i < n; i++){
        if(max_num < nums[i]){
            max_num = nums[i];
            T2_farthest_vertex_2 = i;
        }
    }

    farthest_path_num = max_num;
    r = ceil(double(farthest_path_num)/2.0);
    //cout << "T2-r ->" << r <<endl;

    //T2_center_1を求める
    nums.assign(n, null);
    nums[T2_farthest_vertex_1] = 0;
    dfs1(T2, T2_farthest_vertex_1, 0);
    for(long long i = 0; i < n; i++){
        if(nums[i] == r){
            T2_center_1 = i;
            break;
        }
    }

    //T2_center_2を求める
    nums.assign(n, null);
    nums[T2_farthest_vertex_2] = 0;
    dfs1(T2, T2_farthest_vertex_2, 0);
    for(long long i = 0; i < n; i++){
        if(nums[i] == r){
            T2_center_2 = i;
            break;
        }
    }

    /*
    //確認用
    cout << "T1 : " << endl;
    for(long long i = 0; i < n; i++){
        cout << i << " : ";
        for(long long j = 0; j < T1[i].size(); j++){
            cout << T1[i][j] << " ";
        }cout << endl;
    }cout << endl;

    cout << "T2 : " << endl;
    for(long long i = 0; i < n; i++){
        cout << i << " : ";
        for(long long j = 0; j < T2[i].size(); j++){
            cout << T2[i][j] << " ";
        }cout << endl;
    }cout << endl;

    cout << "farthest_vertexs" << endl;
    cout << "T1_farthest_vertex_1 -> " << T1_farthest_vertex_1 <<endl;
    cout << "T1_farthest_vertex_2 -> " << T1_farthest_vertex_2 <<endl;
    cout << "T2_farthest_vertex_1 -> " << T2_farthest_vertex_1 <<endl;
    cout << "T2_farthest_vertex_2 -> " << T2_farthest_vertex_2 <<endl;

    cout << "centers : " << endl;
    cout << "T1_center_1 -> " << T1_center_1 << endl;
    cout << "T1_center_2 -> " << T1_center_2 << endl;
    cout << "T2_center_1 -> " << T2_center_1 << endl;
    cout << "T2_center_2 -> " << T2_center_2 << endl;
    */

    //isomorphism
    T1_names_1.resize(n, 0);
    T1_names_2.resize(n, 0);
    T2_names_1.resize(n, 0);
    T2_names_2.resize(n, 0);
    
    num = 0;
    dfs2(T1, T1_name_num_1, T1_names_1, T1_center_1, null, 0);
    num = 0;
    dfs2(T1, T1_name_num_2, T1_names_2, T1_center_2, null, 0);
    num = 0;
    dfs2(T2, T2_name_num_1, T2_names_1, T2_center_1, null, 0);
    num = 0;
    dfs2(T2, T2_name_num_2, T2_names_2, T2_center_2, null, 0);

    /*
    //確認用
    cout << "names : " << endl;
    cout << "T1_names_1[T1_center_1] -> " << T1_names_1[T1_center_1] << endl;
    cout << "T1_names_2[T1_center_2] -> " << T1_names_2[T1_center_2] << endl;
    cout << "T2_names_1[T2_center_1] -> " << T2_names_1[T2_center_1] << endl;
    cout << "T2_names_2[T2_center_2] -> " << T2_names_2[T2_center_2] << endl;
    */

    if(T1_names_1[T1_center_1] == T2_names_1[T2_center_1] || T1_names_1[T1_center_1] == T2_names_2[T2_center_2]){
        cout << "Yes" << endl;
    }else if(T1_names_2[T1_center_2] == T2_names_1[T2_center_1] || T1_names_2[T1_center_2] == T2_names_2[T2_center_2]){
        cout << "Yes" << endl;
    }else{
        cout << "No" << endl;
    }

    return 0;
}