zoj 3602 Count the Trees (dfs+哈希)

96 篇文章 0 订阅
64 篇文章 0 订阅

题意:

给出两棵树,问这两棵树有多少对子树,分别来自两棵树且结构相同。


思路:

一开始想着去给没课字符编号,然后map统计,但是没想出编号的办法。

编号的话我们可以根据二叉树每个节点的两个儿子来编号,pair<int,int>pair中两个值分别表示出了两个左右子树的结构,这棵树的结构也就表示出来了,这种做法倒是加深了对树的理解,已经如何构造编号也是深受启发。

然后对两颗树分别dfs就可以了。


但是我在dfs函数里,每次用到pair都重新make_pair结果导致在递归的时候爆栈了,一直segmentation fault,用一个变量记录pair,每次 调用就过了。

不过可气的是一开始用的是C++0x (g++ 4.7.2)交的,原来爆栈的代码往C++ (g++ 4.7.2)一交就过了,编译器的不同造成的结果差异真的很大。。


//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <map>
#include <iostream>
#include <vector>

#define ps push_back
#define LL long long 
#define fir first
#define sec second
#define mk make_pair
using namespace std;
const int maxn=1e6+5;
int cnt, n, m;
struct node
{
    int l,r;
}tree[maxn];
long long ans;
map<pair<int, int>, int>mp[3];
long long book[maxn];

int  dfs(int x, int y)
{
    pair<int, int >e;
    int a, b, i;
    a=b=-1;
    if(tree[x].l!=-1)a=dfs(tree[x].l, y);
    if(tree[x].r!=-1)b=dfs(tree[x].r, y);
    e.fir=a,e.sec=b;
    if(mp[y].find(e)!=mp[y].end())
    {
       i=mp[y][e];
       book[i]++;
       return i; 
    }
    else
    {
       mp[y][e]=cnt++;
       book[cnt-1]++;       
       return cnt-1;
    }
}

int  dfs2(int x)
{
    pair<int, int>e;
    int a, b, i;
    a=b=-1;
    if(tree[x].l!=-1)a=dfs2(tree[x].l);
    if(tree[x].r!=-1)b=dfs2(tree[x].r);
    e.fir=a,e.sec=b;
    if(a==-2 || b==-2)return -2;
    if(mp[0].find(e)!=mp[0].end())
    {
       i=mp[0][e];
       ans+=book[i];
       return i; 
    } 
    else return -2;
}
int main()
{
    int t, i, j, x, y;
    cin>>t;
    while(t--)
    {
        memset(book, 0, sizeof book);
        cnt=0;
        ans=0;
        scanf("%d%d", &n, &m);
        for(i=1; i<=n; i++)
        {
            scanf("%d%d", &tree[i].l, &tree[i].r);
        }
        dfs(1, 0);
        for(i=1; i<=m; i++)
        {
            scanf("%d%d", &tree[i].l, &tree[i].r);
        }
        dfs2(1);
        printf("%lld\n", ans);
        mp[0].clear();
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值