CF762F Tree nesting
问题分析
可以给小树钦定一个根, \(Dp[i][j]\) 表示大树上的点 \(i\) 对应到小树上的点 \(j\) 的可能的方案数。然后每一步转移都是一个状压DP(将小树是否被匹配状压,然后枚举大树上的点和小树上的点匹配)。
但如果这样统计的话,在两种情况下有重复:
- 在小树取不同的根但仍同构;
- 确定小树的根后,小树的子树同构。
所以我们对钦定根后的小树进行哈希,即可排除第一种重复。而如果小树的某两个子树同构,那么就在统计的时候强行钦定一个顺序,这样就解决了第二种重复。
参考程序
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
const int Maxn = 2000;
const int Maxm = 12;
const int MaxAlpha = 1 << Maxm;
int Mod = 1e9 + 7;
struct edge
{
    int To, Next;
    edge() {}
    edge(int _To, int _Next) : To(_To), Next(_Next) {}
};
struct node {
    int Value, Index;
    node() {}
    node(int _Value, int _Index) : Value(_Value), Index(_Index) {}
    inline bool operator<(const node Other) const
    {
        return Value < Other.Value;
    }
};
edge Edge1[Maxn << 1], Edge2[Maxm << 1];
int n, m, Ans;
int Start1[Maxn + 1], Start2[Maxm + 1], Used1, Used2;
int Hash[Maxm + 1], Father[Maxm + 1], Size[Maxm + 1];
int Dp[Maxn + 1][Maxm + 1], F[2][MaxAlpha];
node Temp[Maxm + 1]; int Ctrl[Maxm + 1];
std::set<int> Set;
inline void AddEdge1(int x, int y);
inline void AddEdge2(int x, int y);
inline void Init();
void GetHash(int u, int Fa);
void Calc(int u, int Fa);
int main()
{
    Init();
    for (int i = 1; i <= m; ++i)
    {
        GetHash(i, 0);
        if (Set.count(Hash[i]))
            continue;
        Set.insert(Hash[i]);
        memset(Dp, 0, sizeof(Dp));
        Calc(1, 0);
        for (int j = 1; j <= n; ++j)
            Ans = (Ans + Dp[j][i]) % Mod;
    }
    printf("%d\n", Ans);
    return 0;
}
inline void AddEdge1(int x, int y)
{
    Edge1[++Used1] = edge(y, Start1[x]);
    Start1[x] = Used1;
    return;
}
inline void AddEdge2(int x, int y)
{
    Edge2[++Used2] = edge(y, Start2[x]);
    Start2[x] = Used2;
    return;
}
inline void Init()
{
    scanf("%d", &n);
    for (int i = 1; i < n; ++i)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        AddEdge1(x, y);
        AddEdge1(y, x);
    }
    scanf("%d", &m);
    for (int i = 1; i < m; ++i)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        AddEdge2(x, y);
        AddEdge2(y, x);
    }
    return;
}
void GetHash(int u, int Fa)
{
    Size[u] = 1;
    Father[u] = Fa;
    for (int t = Start2[u]; t; t = Edge2[t].Next)
    {
        int v = Edge2[t].To;
        if (v == Fa)
            continue;
        GetHash(v, u);
        Size[u] += Size[v];
    }
    int Count = 0;
    for (int t = Start2[u]; t; t = Edge2[t].Next)
    {
        int v = Edge2[t].To;
        if (v == Fa)
            continue;
        Temp[++Count] = node(Hash[v], v);
    }
    std::sort(Temp + 1, Temp + Count + 1);
    Hash[u] = 0;
    for (int i = 1; i <= Count; ++i)
    {
        Hash[u] <<= Size[Temp[i].Index] << 1;
        Hash[u] += Hash[Temp[i].Index];
    }
    Hash[u] <<= 1;
    Hash[u] += 1 << ((Size[u] << 1) - 1);
    return;
}
void Calc(int u, int Fa)
{
    for (int t = Start1[u]; t; t = Edge1[t].Next)
    {
        int v = Edge1[t].To;
        if (v == Fa)
            continue;
        Calc(v, u);
    }
    for (int uu = 1; uu <= m; ++uu)
    {
        if (Size[uu] == 1)
        {
            Dp[u][uu] = 1;
            continue;
        }
        int Count = 0;
        memset(Ctrl, 0, sizeof(Ctrl));
        for (int t = Start2[uu]; t; t = Edge2[t].Next)
        {
            int v = Edge2[t].To;
            if (v ==Father[uu]) continue;
            Temp[++Count] = node(Hash[v], v);
        }
        std::sort(Temp + 1, Temp + Count + 1);
        for (int i = 2; i <= Count; ++i)
            if (Temp[i].Value == Temp[i - 1].Value)
                Ctrl[i] = 1;
        memset(F, 0, sizeof(F));
        F[0][0] = 1;
        int Step = 0;
        for (int t = Start1[u]; t; t = Edge1[t].Next)
        {
            int v = Edge1[t].To;
            if (v ==Fa)
                continue;
            for (int j = 0; j < 1 << Count; ++j)
                F[(Step + 1) & 1][j] = 0;
            for (int j = 0; j < 1 << Count; ++j)
                for (int k = 1; k <= Count; ++k)
                {
                    if ((j >> (k - 1)) & 1)
                        continue;
                    if (Ctrl[k] && ((j >> (k - 2)) & 1) == 0)
                        continue;
                    F[(Step + 1) & 1][j | (1 << (k - 1))] += 1LL * F[Step & 1][j] * Dp[v][Temp[k].Index] % Mod;
                    F[(Step + 1) & 1][j | (1 << (k - 1))] %= Mod;
                }
            for (int j = 0; j < 1 << Count; ++j)
            {
                F[(Step + 1) & 1][j] += F[Step & 1][j];
                F[(Step + 1) & 1][j] %= Mod;
            }
            ++Step;
        }
        Dp[u][uu] = F[Step & 1][(1 << Count) - 1];
    }
    return;
}
CF762F Tree nesting的更多相关文章
- 『Tree nesting 树形状压dp 最小表示法』
		Tree nesting (CF762F) Description 有两个树 S.T,问 S 中有多少个互不相同的连通子图与 T 同构.由于答案 可能会很大,请输出答案模 1000000007 后的值 ... 
- [Educational Round 17][Codeforces 762F. Tree nesting]
		题目连接:678F - Lena and Queries 题目大意:给出两个树\(S,T\),问\(S\)中有多少连通子图与\(T\)同构.\(|S|\leq 1000,|T|\leq 12\) 题解 ... 
- [Codeforces]762F - Tree nesting
		题目大意:给出一棵n个点的树和一棵m个点的树,问第一棵树有多少个连通子树与第二棵树同构.(n<=1000,m<=12) 做法:先找出第二棵树的重心(可能为边),以这个重心为根,可以避免重复 ... 
- Educational Codeforces Round 17F Tree nesting
		来自FallDream的博客,未经允许,请勿转载, 谢谢. 给你两棵树,一棵比较大(n<=1000),一棵比较小(m<=12) 问第一棵树中有多少个连通子树和第二棵同构. 答案取膜1e9+ ... 
- Educational Codeforces Round 17
		Educational Codeforces Round 17 A. k-th divisor 水题,把所有因子找出来排序然后找第\(k\)大 view code //#pragma GCC opti ... 
- [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法
		二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ... 
- SAP CRM 树视图(TREE VIEW)
		树视图可以用于表示数据的层次. 例如:SAP CRM中的组织结构数据可以表示为树视图. 在SAP CRM Web UI的术语当中,没有像表视图(table view)或者表单视图(form view) ... 
- 无限分级和tree结构数据增删改【提供Demo下载】
		无限分级 很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了. 说到无限分级,又要扯到递归调用了.(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据.当然,以 ... 
- 2000条你应知的WPF小姿势 基础篇<45-50 Visual Tree&Logic Tree 附带两个小工具>
		在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ... 
随机推荐
- 缓存策略:redis缓存之springCache
			最近通过同学,突然知道服务器的缓存有很多猫腻,这里通过网上查询其他人的资料,进行记录: 缓存策略 比较简单的缓存策略: 1.失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放 ... 
- 连接云服务器中MySql数据库遇到的问题
			使用的免费的云服务器,上面只能下载MySql数据库,不过当云数据库使用绰绰有余了,也就放一些测试数据而已 而且上面只可以部署php项目,.netcore项目部署实现比较麻烦 问题如下: 下载了navi ... 
- C# 定义热键
			using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ... 
- 动画方案 Lottie 学习(一)之基础
			参考 lottie系列文章(一):lottie介绍 lottie系列文章(二):lottie最佳实践 lottie系列文章(三):动画设计规范 lottie系列文章(四):源码分析——svg渲染 
- JS基础_for循环练习3
			<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ... 
- vue之scoped穿透
			vue之scoped穿透 问题:在页面中,需要了第三方插件的样式,又不想取消scoped,防止造成样式污染 方法:>>> 代码: #tab >>> .ivu-tab ... 
- 帝国cms常用标签
			.loop获取时间标签 /*获取年月日,时分秒.可以按照自己的需求单独获取年,或者月.*/ <?=date("Y-m-d H:i:s",$bqr[newstime])?> ... 
- vscode 头部注释插件
			1.安装 在vs商店搜索koroFileHeader 2.进入vscode的设置里边搜索fileheader.customMade 3.修改配置信息 "fileheader.customMa ... 
- python部署到服务器(1) 一一 搭建环境
			本机环境说明 linux下的CentOS 7, 自带python2.7.5, 使用 python --version 命令查看,因系统需要python2.7.5,因此我们并不卸载,另外安装python ... 
- 写Java也得了解CPU–CPU缓存
			CPU,一般认为写C/C++的才需要了解,写高级语言的(Java/C#/pathon…)并不需要了解那么底层的东西.我一开始也是这么想的,但直到碰到LMAX的Disruptor,以及马丁的博文,才发现 ... 
