题目连接

问题分析

可以给小树钦定一个根, \(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的更多相关文章

  1. 『Tree nesting 树形状压dp 最小表示法』

    Tree nesting (CF762F) Description 有两个树 S.T,问 S 中有多少个互不相同的连通子图与 T 同构.由于答案 可能会很大,请输出答案模 1000000007 后的值 ...

  2. [Educational Round 17][Codeforces 762F. Tree nesting]

    题目连接:678F - Lena and Queries 题目大意:给出两个树\(S,T\),问\(S\)中有多少连通子图与\(T\)同构.\(|S|\leq 1000,|T|\leq 12\) 题解 ...

  3. [Codeforces]762F - Tree nesting

    题目大意:给出一棵n个点的树和一棵m个点的树,问第一棵树有多少个连通子树与第二棵树同构.(n<=1000,m<=12) 做法:先找出第二棵树的重心(可能为边),以这个重心为根,可以避免重复 ...

  4. Educational Codeforces Round 17F Tree nesting

    来自FallDream的博客,未经允许,请勿转载, 谢谢. 给你两棵树,一棵比较大(n<=1000),一棵比较小(m<=12) 问第一棵树中有多少个连通子树和第二棵同构. 答案取膜1e9+ ...

  5. Educational Codeforces Round 17

    Educational Codeforces Round 17 A. k-th divisor 水题,把所有因子找出来排序然后找第\(k\)大 view code //#pragma GCC opti ...

  6. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  7. SAP CRM 树视图(TREE VIEW)

    树视图可以用于表示数据的层次. 例如:SAP CRM中的组织结构数据可以表示为树视图. 在SAP CRM Web UI的术语当中,没有像表视图(table view)或者表单视图(form view) ...

  8. 无限分级和tree结构数据增删改【提供Demo下载】

    无限分级 很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了. 说到无限分级,又要扯到递归调用了.(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据.当然,以 ...

  9. 2000条你应知的WPF小姿势 基础篇<45-50 Visual Tree&Logic Tree 附带两个小工具>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ...

随机推荐

  1. 牛客 158D a-贝利福斯数

    将所有形如ax+1的数称为a-贝利福斯数,其中x是正整数.一个a-贝利福斯数是a-贝利福斯素数,当且仅当它不能被分解成两个a-贝利福斯数的积.现在给出a,n,问有多少个 ≤ n的a-贝利福斯数可以被分 ...

  2. .Net面试题三

    1..Net中类和结构的区别? 2.死锁地必要条件?怎么克服? 3.接口是否可以继承接口?抽象类是否可以实现接口?抽象类是否可以继承实体类? 4.构造器COnstructor是否可以被继承?是否可以被 ...

  3. c#中异常捕获,回滚

    语法: try { 有可能出现错误的代码写在这里 } catch { 出错后的处理 } 如果try中的代码没有出错,则程序正常运行try中的内容后,不会执行catch中的内容, 如果try中的代码一但 ...

  4. golang(10):web开发 & 连接数据库

    http编程 ) Go原生支持 http : import ("net/http") ) Go 的 http 服务性能和 nginx 比较接近 ) 几行代码就可以实现一个 web ...

  5. 学习笔记--三分法&秦九韶算法

    前言 其实也没什么好说的吧,三分法就是用来求一个单调函数的最值和满足最大值的\(x\),秦九韶算法就是在\(O(N)\)时间内求一个多项式值 怎么用 三分法使用--看这篇:https://www.cn ...

  6. js弹窗返回值详解(window.open方式)

    今天在改公司一个老系统时,碰到了window.open()的这个语法.虽然这个方法有点老,不太用了.所以有点不清楚父级弹框如何获取子级页面返回的值.为了解决这个问题,上网搜了一下.原作者参考网址:ht ...

  7. python视频学习笔记6(名片管理系统开发)

    cards_main.py主函数 cards_tools.py -------------------------------------------------------------------- ...

  8. 使用PyQt5自制文件查找工具,并生成EXE文件

    一.工作中,有一个关键词查找工作,查找开发版本中使用的文本,有哪些词语是非法的,一个一个去查太累了,所以想到了用代码来实现.可后来想想,能否做成简单的小工具,大家都可以使用. 于是就着手编写工具.原来 ...

  9. Java学习笔记【十一、序列化】

    序列化的条件 实现Serializable接口 所有属性必须是可序列化的,或标记为transient(不做序列化) 序列化-将对象输出为序列化文件 ObjectOutputStream 反序列化-将序 ...

  10. 【1】Zookeeper概述

    一.前言 在"网络是不可靠的"这一前提下,分布式系统开发需要解决如下四个问题: 客户端如何访问众多服务?  解决方案:服务聚合,使用API网关 服务于服务之间如何通信?  解决方案 ...