码迷,mamicode.com
首页 > 其他好文 > 详细

树的杂记

时间:2015-07-05 19:52:51      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:

某次模拟赛的T2 强迫症

题目大意:判断一棵树是否对称。

思路:首先,一棵树的重心一定在对称轴上。一棵树是否对称有两种情况:有点在对称轴上和没有点在对称轴上。没有点在对称轴上的情况一定有两个重心(但有两个重心并不一定没有点在对称轴上)。有两个重心时,我们只需要算出两个重心对应子树的hash值,然后比较,如果相等就对称,否则就选其中一个重心(可以任选,并不影响结果)按一个重心的情况做一遍;有一个重心【可以有两棵单独的自己对称的树】(或上述再做一遍的情况【只能有一棵单独的自己对称的树】)时,我们计算出这个重心所有子树的hash值,放到map里,计算出hash值对应为奇数的hash值个数,如果超过了能单独自己对称树的个数就不对称,否则就判断这棵树能否自己对称【同样只能有一棵单独的自己对称的树】,递归下去。

         考试的时候,穷举了根,就会忽略没有点在对称轴上的情况,同时没有想到很好的hash,所以就导致了分数不高。

         这道题目的hash的选择要十分小心,很多基于子树的hash如果拆开后可能会出现bug。所以在这道题中应用了位运算(异或是没有分配律的,所以可以避免很多问题)。

技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<cstdlib>
#include<ctime>
#define maxnode 10005
#define pp 233
using namespace std;
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},tot=0,
    root1,root2,maxsiz,n,siz[maxnode]={0},ha[30]={0};
char color[maxnode]={0};
map <unsigned long long,int> cnt,dui;
void add(int u,int v)
{
    ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;
    ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;
}
void getroot(int u,int fa)
{
    int i,j,mm=0;
    siz[u]=1;
    for (i=point[u];i;i=next[i])
        if ((j=en[i])!=fa)
        {
            getroot(j,u);siz[u]+=siz[j];mm=max(mm,siz[j]);
        }
    mm=max(mm,n-siz[u]);
    if (mm<=maxsiz)
    {
        if (mm<maxsiz){maxsiz=mm;root1=u;root2=0;}
        else root2=u;
    }
}
unsigned long long gethash(int u,int fa)
{
    int i,j;
    unsigned long long ss=0;
    for (i=point[u];i;i=next[i])
        if ((j=en[i])!=fa)
            ss+=gethash(j,u);
    return (ss*pp)^(ha[color[u]-A]);
}
bool judge(int r1,int r2,int fa,int cn)
{
    int i,j,x,y,cc=0,zhan[3]={0};
    unsigned long long ss,s1,s2;
    if (r2==0)
    {
        cnt.clear();dui.clear();
        for (i=point[r1];i;i=next[i])
        {
            if ((j=en[i])==fa) continue;
            ss=gethash(j,r1);
            if (!cnt.count(ss)) cnt[ss]=0;
            ++cnt[ss];dui[ss]=j;
        }
        map<unsigned long long,int>::iterator it;
        for (it=cnt.begin();it!=cnt.end();++it)
            if (it->second %2==1) 
            {
              ++cc;if (cc<=cn) zhan[cc]=dui[it->first];
            }
        if (cc>cn) return false;
        for (i=1;i<=cc;++i)
            if (!judge(zhan[i],0,r1,1)) return false;
        return true;
    }
    else
    {
        s1=gethash(r1,r2);s2=gethash(r2,r1);
        if (s1==s2) return true;
        return (judge(r1,0,0,2));
    }
}
int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    
    int t,i,j,u,v;
    srand(time(0));
    for (i=0;i<26;++i) ha[i]=rand();
    scanf("%d",&t);
    while(t)
    {
        scanf("%d",&n);tot=0;
        memset(point,0,sizeof(point));
        memset(next,0,sizeof(next));
        for (i=1;i<=n;++i)
            while(scanf("%c",&color[i])==1)
              if (color[i]>=A&&color[i]<=Z) break;
        for (i=1;i<n;++i)
        {
            scanf("%d%d",&u,&v);add(u,v);
        }
        maxsiz=n;getroot(1,root1=root2=0);
        if (judge(root1,root2,0,2)) printf("SYMMETRIC\n");
        else printf("NOT SYMMETRIC\n");
        --t;
    }
    
    fclose(stdin);
    fclose(stdout);
}
View Code

 

树的杂记

标签:

原文地址:http://www.cnblogs.com/Rivendell/p/4622742.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!