uva12489 Combating cancer(树同构)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3933

给你两棵无根树,让你判断这两棵树是否同构

不会判断树同构,果断抄了个模板,乱搞给过掉了。

首先由于给的是无根树,而要判断无根树是否同构得以重心为根,然后做一个括号序列的哈希。

于是我们需要先找出重心,要找树的重心得先知道直径。

找出直径,直径上的点的个数是偶数,那么重心是中间的两个点,如果是奇数个,那么重心是中间那个。

或者说是根据拓排,每次度数为1的点入队,留下的最后一批就是。

然而我当时脑抽了一下,求好直径,后用第二种再去搞。。。其实求直径的时候保存一下路径就好了。

最后,如果有两个重心就做两次哈希,得到两个哈希值,一个就一次。

最后把两棵树的哈希值比一下是否有相同的。

/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author xyiyy @https://github.com/xyiyy
 */

#include <iostream>
#include <fstream>

//#####################
//Author:fraud
//Blog: http://www.cnblogs.com/fraud/
//#####################
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <sstream>
#include <ios>
#include <iomanip>
#include <functional>
#include <algorithm>
#include <vector>
#include <string>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <climits>
#include <cctype>

using namespace std;
#define pb(X) push_back(X)
#define rep(X, N) for(int X=0;X<N;X++)
#define ALL(X) (X).begin(),(X).end()
typedef unsigned long long ull;

const int maxNode = 10010;
const int maxEdge = (maxNode << 1);
//
// Created by xyiyy on 2015/8/14.
//

#ifndef ICPC_HASHTREE_HPP
#define ICPC_HASHTREE_HPP

//树的同构,返回哈希值
//输入有根树的根,或者无根树的重心
typedef unsigned long long ull;
const ull MAGIC = 321;

//
// Created by xyfra_000 on 2015/8/14.
//

#ifndef ICPC_ADJLIST_ARRAY_HPP
#define ICPC_ADJLIST_ARRAY_HPP

#define Foredge(A, X) for(int A = From[X];A!=-1;A = Next[A])

int From[maxEdge], To[maxEdge];
int Next[maxEdge];
int Edgecnt;

void init(int n) {
    rep(i, n + 1)From[i] = -1;
    Edgecnt = 0;
}

void addedge(int u, int v) {
    To[Edgecnt] = v;
    Next[Edgecnt] = From[u];
    From[u] = Edgecnt++;
}

#endif //ICPC_ADJLIST_ARRAY_HPP

ull powMod(ull a, int n) {
    ull ret = 1ULL;
    while (n) {
        if (n & 1)ret *= a;
        a *= a;
        n >>= 1;
    }
    return ret;
}

struct Hash {
    int length;
    ull value;

    Hash() : length(0), value(0) { }

    Hash(char c) : length(1), value(c) { }

    Hash(int l, int v) : length(l), value(v) { }
};

bool operator<(const Hash &a, const Hash &b) {
    return a.value < b.value;
}

Hash operator+(const Hash &a, const Hash &b) {
    return Hash(a.length + b.length, a.value * powMod(MAGIC, b.length) + b.value);
}

void operator+=(Hash &a, Hash &b) {
    a = a + b;
}

vector<Hash> childs[maxNode];

Hash dfs(int pre, int cur) {
    Hash ret;
    childs[cur].clear();
    for (int iter = From[cur]; iter != -1; iter = Next[iter]) {
        if (To[iter] != pre) {
            childs[cur].pb(dfs(cur, To[iter]));
        }
    }
    sort(ALL(childs[cur]));
    for (vector<Hash>::iterator iter = childs[cur].begin(); iter != childs[cur].end(); iter++) {
        ret += *iter;
    }
    Hash retL = Hash(‘(‘);
    ret = ‘(‘ + ret + ‘)‘;
    return ret;
}

ull getHash(int root) {
    return dfs(-1, root).value;
}

#endif //ICPC_HASHTREE_HPP

//
// Created by xyfra_000 on 2015/8/14.
//

#ifndef ICPC_TREEDIAMETER_HPP
#define ICPC_TREEDIAMETER_HPP

//求树的直径
//可以通过修改dfs部分变成求带权的树的直径

vector<int> dist;

void dfs(int p, int u, int d) {
    dist[u] = d;
    Foredge(i, u) {
        if (To[i] != p) {
            dfs(u, To[i], d + 1);
        }
    }
}

int getDiameter(int n) {
    dist.resize(n);
    dfs(-1, 0, 0);
    int u = max_element(ALL(dist)) - dist.begin();
    dfs(-1, u, 0);
    return *max_element(ALL(dist));
}

#endif //ICPC_TREEDIAMETER_HPP

int deg[maxNode];
int vis[maxNode];

class TaskH {
public:
    void solve(std::istream &in, std::ostream &out) {
        int n;
        while (in >> n) {
            vector<ull> ans[2];
            rep(times, 2) {
                int u, v;
                init(n);
                rep(i, n + 1)deg[i] = 0;
                rep(i, n + 1)vis[i] = 0;
                queue<int> q;
                rep(i, n - 1) {
                    in >> u >> v;
                    u--, v--;
                    deg[u]++;
                    deg[v]++;
                    addedge(u, v);
                    addedge(v, u);
                }
                int dia = getDiameter(n);
                int num = n;
                rep(i, n) {
                    if (deg[i] == 1) {
                        q.push(i);
                    }
                }
                int gao = 1;
                if (dia & 1)gao++;
                while (num > gao && !q.empty()) {
                    u = q.front();
                    q.pop();
                    vis[u] = 1;
                    num--;
                    deg[u]--;
                    for (int i = From[u]; i != -1; i = Next[i]) {
                        int v = To[i];
                        if (!vis[v]) {
                            deg[v]--;
                            if (deg[v] == 1) {
                                q.push(v);
                            }
                        }
                    }
                }
                rep(i, n) {
                    if (!vis[i]) {
                        ans[times].pb(getHash(i));
                    }
                }
            }
            bool ok = 0;
            rep(i, ans[0].size()) {
                rep(j, ans[1].size()) {
                    if (ans[0][i] == ans[1][j])ok = 1;
                }
            }
            if (ok)out << "S" << endl;
            else out << "N" << endl;
        }
    }
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    TaskH solver;
    std::istream &in(std::cin);
    std::ostream &out(std::cout);
    solver.solve(in, out);
    return 0;
}
时间: 2024-11-25 08:19:22

uva12489 Combating cancer(树同构)的相关文章

『Andrew and Chemistry 树同构』

Andrew and Chemistry Description During the chemistry lesson Andrew learned that the saturated hydrocarbons (alkanes) enter into radical chlorination reaction. Andrew is a very curious boy, so he wondered how many different products of the reaction m

【BZOJ3162】独钓寒江雪 树同构+DP

[BZOJ3162]独钓寒江雪 题解:先进行树hash,方法是找重心,如果重心有两个,则新建一个虚点将两个重心连起来,新点即为新树的重心.将重心当做根进行hash,hash函数不能太简单,我的方法是:将x的所有儿子的hash值排序,然后将这些hash值立方合在一起作为x的hash值. 进行完树hash后,我们考虑DP.首先不考虑同构,设f[0/1][x]表示选(不选)x时,在x的子树中选出独立集的方案数,则有 $f[0][x]=\prod f[1][y]+f[0][y]\\f[1][x]=\pr

BZOJ 3197 Sdoi2013 assassin 动态规划+树同构+费用流

题目大意:给定一棵树和两组权值,求第一组权值最少改变多少个之后这棵树经过重标号之后与第二组权值相同 这个题做法很神- - 首先和3162一样的处理方式 我们先找到这棵树的重心作为根 如果重心有两个就新建一个根连向这两个重心 令f[x][y]表示x所在子树的第一组权值和y所在子树的第二组权值匹配的最小花销 转移的必要条件是x所在的子树与y所在的子树同构且x与y深度相同 为了保证无后效性,x的所有子节点与y的所有子节点之间的最小花销必须都已求出 那么我们将节点以深度的倒数为第一键值,Hash值为第二

【BZOJ3197】[Sdoi2013]assassin 树同构+动态规划+KM

[BZOJ3197][Sdoi2013]assassin Description Input Output Sample Input 4 1 2 2 3 3 4 0 0 1 1 1 0 0 0 Sample Output 1 HINT 题意:给你两棵同构的树,每个节点都有权值0/1,现在想改变第一棵树中部分点的权值,使得两棵树对应的节点权值相同,问最少改变多少节点. 题解:先考虑树hash+树形DP.树hash的方法同独钓寒江雪.设f[x][y]表示第一棵树中的x节点与第二棵树中的y节点对应时,

luogu P5043 【模板】树同构([BJOI2015]树的同构)

题面: 树是一种很常见的数据结构. 我们把N个点,N−1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如果能够把树T1的所有点重新标号,使得树T1和树T2完全相同,那么这两个树是同构的.也就是说,它们具有相同的形态. 现在,给你M个有根树,请你把它们按同构关系分成若干个等价类. 无根树Hash... 以树的每一个节点为根,求出Hash值后,存入一个数组里,排序. 比对就像这样 for(int j=1;j<=i;j++

Regular Forestation CodeForces - 1252F(树同构)

Regular Forestation \[ Time Limit: 1000 ms\quad Memory Limit: 262144 kB \] 题意 给出一个节点为 \(n\) 的树,问删掉树上的一个点和这个点相连的边以后,剩下的子树是不是都是同构的. 思路 首先删掉的这个点一定是这棵树的重心,而且一棵树的重点至多只会有两个. 那么就暴力枚举判断删掉这棵树的重心,然后对于剩下的子树去判断是否是同构的. 判断两棵树是否是同构的,也是先找出重心,然后从重心开始,用进某个节点为 \(0\) 表示

BZOJ 3162 独钓寒江雪 树同构+树形DP

题目大意:给定一棵树,求本质不同的独立集个数对1000000007取模后的值 首先独立集个数应该都会求吧- - 令f[x][0]为x这个点不选的独立集个数 f[x][1]为x这个点选的独立集个数 那么有f[x][0]=Σf[son[x]][0]+f[son[x]][1] f[x][1]=Σf[son[x]][0] 但是现在要求本质不同 说到本质不同我们很容易想到群论 但是群论显然写不了- - 于是我们考虑对树进行一下处理 首先将树有根化 为了保证形态相同的子树在有根化之后形态依然相同,我们需要找

BZOJ 3899 仙人掌树的同构 仙人掌同构+KMP算法

题目大意:给定一棵仙人掌,求有多少自同构 仙人掌同构问题= = 曾经出过一个判断两个仙人掌是否同构的题,感觉和这个题很类似 首先假设这是一棵树,考虑怎么做 我们首先找到树的重心(如果有两个就在中间加一个点变成一个) 然后把树Hash 对于一棵树 如果某一哈希值的子树有k个 就把答案乘上一个k! 现在变成了仙人掌,那么我把每个环变成一个红点连向环上的所有点,然后把原先环上的边拆除,可以得到一棵树,按树同构做就行了 为了区分红点和普通点的区别,需要为红点设置不同的哈希参数 但是这样有一个BUG,就是

[BZOJ4337][BJOI2015]树的同构(树的最小表示法)

4337: BJOI2015 树的同构 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1023  Solved: 436[Submit][Status][Discuss] Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如果能够把树T1的所有点重新标号,使得树T1和树T2完全相 同,那么这两个树是同