算法设计与优化编程 第十讲 Subway

本文介绍了一种解决地铁线路名称变更后,通过构建哈希函数实现新旧线路同构匹配的方法。利用树的中点及子树哈希值进行比对,确保即便地铁站名改变也能准确找到对应的线路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Subway

Problem Description

jiefangxuanyan and yiyi cat are universally acknowledged model couples(配偶). Once jiefangxuanyan has time, he takes a train to yiyi cat’s city and meets her. This time, as usual, jiefangxuanyan gets out from the railway station, and enters the subway, only to find that the subway stations of the whole city changes their names!
As a direction idiot(白痴), jiefangxuanyan felt helpless with this situation. He called yiyi cat for help. Because the subway map is so complicated, she can’t remember it either. Fortunately, only the names of the stations changed, the structure of subway lines is the same. So she picks out the old map to make a mapping.
But mapping such a confused(迷乱的) subway map is definitely a difficult task. So she has to use the computer. Unfortunately, she just spilt(泼出,洒出) wonton(馄饨) soup(汤) into her computer. So, yiyi cat asked you for help, hoping you can help her with this problem.
The subway in the city forms a tree, with N subway stations and N-1 subway lines. Any pair of stations are connected with one or more subway lines. You need to find a bijective(双射) mapping from the old names to the new names, that for each pair of stations connected by exactly one line in the old map, their new names are also connected by exactly one line in the new map.

Input

The input has multiple test cases, please process to the end of file.
For each test case, the first line is an integer N (1≤N≤100000) .
In the following N−1 lines, each line has two space-separated strings, as two stations connected by one line in the old map.
In the following N−1 lines, each line has two space-separated strings, as two stations connected by one line in the new map.
Station names are no longer than 10 characters, and only consists of lowercase letters (a~z).

Output

For each test case, output N lines.
Each line consists two space-separated strings, as the old name and its corresponding new name.
Both the names appeared in the old and new subway map should appear exactly once in the output.
You can output the names in any order. And if there are multiple valid mappings, output any one.
Names in the old map and the new map may be the same, but this does not mean these two stations are the same.

Sample Input

3
a b
b c
b a
a c

Sample Output

b a
a b
c c

这里写图片描述

思路:

这个题是一个树的同构判断,想办法用一个和节点顺序无关的哈希函数将树表示出来即可。
这里提供一种方法:首先求解树的中点,然后将中点作为根。只有一个结点的子树哈希值为1。选一个比较大的质数P和一个特别大的质数Q。对于每一颗树,把它的所有子树的哈希值排序。然后hash=sum(P^i∗hash[i])%Q,就能算出来总体的哈希值。有两个中点的树两个中点都试一下。为了保险可以检查下哈希值有没有重的。

代码

#include <cstring>
#include <fstream>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <iostream>
#include <new>
using std::string;
using std::cin;
using std::cout;
const int N=110000;


struct Metro{
    std::map<string,int> mp;
    std::vector<string> vec;

    //调用分配程序,把字符编号的顶点换成整数编号的顶点
    int alloc(const string &name){

        //迭代器iterator
        std::pair<std::map<string,int>::iterator,bool> got=mp.insert(std::make_pair(name,mp.size()));

        //如果得到第二个点
        if(got.second){
            vec.push_back(name);
        }
        return got.first->second;
    }
};

//定义item结构体
struct item{
    int tgt;
    item *next;
    item(){}
    item(int tgt,item *next):tgt(tgt),next(next){}
}*ls[N],*lt[N],storage[4*N];

//插入边
void insert(item **list,int a,int b,item *&loc){
    list[a]=new(loc++) item(b,list[a]);
    list[b]=new(loc++) item(a,list[b]);
}

int farSel[N];
std::pair<int,int> findFarthest(item **list,int a,int prev){
    std::pair<int,int> r(a,-1);
    for(item *p=list[a];p;p=p->next){
        if(p->tgt!=prev){
            std::pair<int,int> cur=findFarthest(list,p->tgt,a);
            if(cur.second>r.second){
                farSel[a]=p->tgt;
                r=cur;
            }
        }
    }
    r.second++;
    return r;
}

//找树的中点
std::pair<int,int> findRoot(item **list){
    int a=findFarthest(list,0,-1).first;
    std::pair<int,int> t=findFarthest(list,a,-1);
    for(int i=0;i<t.second/2;i++){
        a=farSel[a];
    }
    return std::make_pair(a,t.second%2?farSel[a]:-1);
}
const int M=1000000007,MM=100000007;
struct HashPair{
    int a,h;
    HashPair(){}
    HashPair(int a,int h):a(a),h(h){}
    bool operator<(const HashPair &x)const{
        return h<x.h;
    }
};

//求哈希值
std::vector<HashPair> hs[N],ht[N];
int hash(item **list,int a,int prev,std::vector<HashPair> *tgt){
    std::vector<HashPair> vec;
    for(item *p=list[a];p;p=p->next){
        if(p->tgt!=prev){
            vec.push_back(HashPair(p->tgt,hash(list,p->tgt,a,tgt)));
        }
    }
    std::sort(vec.begin(),vec.end());
    int r=1;
    for(int i=0;i<(int)vec.size();i++){
        r=((long long)r*MM+vec[i].h)%M;
    }
    tgt[a].swap(vec);
    return r;
}

bool match(std::vector<HashPair> &vs,std::vector<HashPair> &vt,int *res){
    if(vs.size()!=vt.size()){
        return false;
    }
    for(int i=0;i<(int)vs.size();i++){
        for(int j=i;j<(int)vt.size()&&vt[j].h==vs[i].h;j++){
            std::swap(vt[i].a,vt[j].a);
            if(match(hs[vs[i].a],ht[vt[i].a],res)){
                goto lblMatch;
            }
        }
        return false;
lblMatch:
        res[vs[i].a]=vt[i].a;
    }
    return true;
}
int mapping[N];

int main(){
    int size = 8 << 20;
    char *p = (char*)malloc(size) + size;
    //__asm__("movl %0, %%esp\n" :: "r"(p));
    //std::ifstream fin("in.txt");
    //std::ofstream fout("out.txt");
    int n;

    //输入边
    while(cin>>n){
        memset(ls,0,sizeof(ls));
        item *loc=storage;      
        Metro src;

        //转换成整数
        for(int i=0;i<n-1;i++){
            string name;
            cin>>name;
            int a=src.alloc(name);
            cin>>name;
            int b=src.alloc(name);
            insert(ls,a,b,loc);
        }
        memset(lt,0,sizeof(lt));
        Metro tgt;
        //转换成整数
        for(int i=0;i<n-1;i++){
            string name;
            cin>>name;
            int a=tgt.alloc(name);
            cin>>name;
            int b=tgt.alloc(name);
            insert(lt,a,b,loc);
        }
        //找树根(中点)
        std::pair<int,int> rs=findRoot(ls),rt=findRoot(lt);
        std::vector<HashPair> vs,vt;

        //求树根哈希值
        vs.push_back(HashPair(rs.first,hash(ls,rs.first,rs.second,hs)));

        //处理第一个中点
        if(rs.second!=-1){
            vs.push_back(HashPair(rs.second,hash(ls,rs.second,rs.first,hs)));
        }

        //排序,提高速度
        std::sort(vs.begin(),vs.end());

        vt.push_back(HashPair(rt.first,hash(lt,rt.first,rt.second,ht)));

        //处理第二个中点
        if(rs.second!=-1){
            vt.push_back(HashPair(rt.second,hash(lt,rt.second,rt.first,ht)));
        }

        //排序,提高速度
        std::sort(vt.begin(),vt.end());

        //判断是否同构
        if(match(vs,vt,mapping)){
            for(int i=0;i<n;i++){

                //打印同构
                cout<<src.vec[i]<<' '<<tgt.vec[mapping[i]]<<'\n';
            }
        }else{
            cout<<"TAT\n";
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值