树的最小表示法 UVA 12489 - Combating cancer

mark一下:

对于一个有根树,我们可以通过比较他们的括号序列的最小表示,如果他们的括号序列最小表示完全相等,那么他们同构

https://www.byvoid.com/blog/directed-tree-bracket-sequence

 

dfs进入某个子树用 '(' 表示,dfs结束用')'表示,这样就将一颗树转化成一个括号序列

只需将括号序列变成最小表示,就可以比较两棵树是否同构。但复杂度好像很高的样子...

回到树上来说,比较两棵子树的大小,可以先比较两个顶点的度,如果度相等,则递归比较子树。则可以看成是求一个最小的度序列

括号序列的另一个理解,就是poj上某道题。'('可以看成0,可以理解为向远离根节点的节点走,')'可以看成1,回溯,往回走。

于是比较两棵子树的大小,可以将两个01序列,看做为字符串,求最小表示。

不管是哪种序列,都可以作为树的最小表示。序列求出来,我们可以用 子序列排序+hash 得到一个新的序列,最后得到树的最小表示hash值。复杂度nlogn。

快速的算法可以参考 <Hash在信息学竞赛中的一类应用-杨弋>。

 

无根树可以通过一次拓扑排序,将整棵树收缩,最后只剩下一个点或者是两个点。枚举根即可。

 

贴一下UVA 12489 - Combating cancer 的代码,一脸水过的样子,不知道为什么用度序列hash连样例都过不了,01序列hash就过了。

hash函数找CJboy要的一个字符串hash的函数,不明觉厉~~

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<iostream>

using namespace std;

#define For(i,forN) for(int i=0;i<forN;i++)
#define ForEdge(i,u) for(int i=head[u];i!=-1;i=edge[i].next)
#define sf  scanf
#define pf  printf
#define mp  make_pair

#define _clr(x,y)   memset(x,(y),sizeof(x))

typedef unsigned int UI ;
const int Maxn=21000,Mod=2081,hx=557,hy=131;
/*
    判断树的同构,用此hash函数:
*/
int head[Maxn],etot,Cc[Maxn];
int n;
UI  Hash[Maxn];
bool vis[Maxn];

struct Edge
{
    int to,next;
}edge[Maxn*2];

void init_edge()
{
    etot=0;
    _clr(head,-1);
}

void add_edge(int u,int v)
{
    edge[etot].to=v;
    edge[etot].next=head[u];
    head[u]=etot++;
}

void dfs(int u)
{
    vis[u]=true;
    vector < int > Ve;
    ForEdge(i,u)
    {
        int v=edge[i].to;
        if(!vis[v])
        {
            dfs(v);
            Ve.push_back(Hash[v]);
        }
    }
    sort(Ve.begin(),Ve.end());  Ve.push_back(1);//可以看做字符')',或者1
    UI b = 378551 , a = 63689;
    Hash[u]=0;//可以看做字符'(',或者0
    For(i,Ve.size())
    {
        Hash[u]=Hash[u]*a+Ve[i];
        a*=b;
    }
    Hash[u]&=0x7FFFFFFF;
}

int din[Maxn],stk[Maxn],top;
int ans[2][2];

int main()
{
    while(~sf("%d",&n))
    {
        int tid[2]={0};
        for(int cas=0;cas<2;cas++)
        {
            init_edge();
            int u,v;
            queue < int > q;
            _clr(din,0);
            for(int i=1;i<n;i++)
            {
                sf("%d%d",&u,&v);
                din[u]++,din[v]++;
                add_edge(u,v);
                add_edge(v,u);
            }
            int last=n;
            _clr(vis,false);
            for(int i=1;i<n+1;i++)
            {
                if(din[i]==1)   q.push(i),last--,vis[i]=true;
            }
            while(last!=0 && !q.empty())
            {
                u=q.front();    q.pop();    din[u]--;
                ForEdge(i,u)
                {
                    int v=edge[i].to;
                    if(!vis[v])
                    {
                        din[v]--;
                        if(din[v]==1)
                        q.push(v),last--,vis[v]=true;
                    }
                }
            }
            for(int i=1;i<=n;i++)
            {
                if(din[i]==1)
                {
                    _clr(vis,false);    dfs(i);
                    ans[cas][tid[cas]++]=Hash[i];
                    if(tid[cas]>2)  while(1);
                }
            }
        }
        bool flag=false;
        for(int i=0;i<tid[0];i++)
        for(int j=0;j<tid[1];j++)
        if(ans[0][i] == ans[1][j])
        flag=true;
        if(flag)    puts("S");
        else    puts("N");
    }
    return 0;
}

 

posted @ 2013-11-04 12:06  phk52  阅读(686)  评论(0编辑  收藏  举报