4455: [Zjoi2016]小星星

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 204  Solved: 137
[Submit][Status][Discuss]

Description

小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品。她有n颗小星星,用m条彩色的细线串了起来,每条细线连着两颗小星星。有一天她发现,她的饰品被破坏了,很多细线都被拆掉了。这个饰品只剩下了n?1条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树。小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星。如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上也有细线相连。小Y想知道有多少种可能的对应方式。只有你告诉了她正确的答案,她才会把小饰品做为礼物送给你呢。

Input

第一行包含个2正整数n,m,表示原来的饰品中小星星的个数和细线的条数。
接下来m行,每行包含2个正整数u,v,表示原来的饰品中小星星u和v通过细线连了起来。
这里的小星星从1开始标号。保证u≠v,且每对小星星之间最多只有一条细线相连。
接下来n-1行,每行包含个2正整数u,v,表示现在的饰品中小星星u和v通过细线连了起来。
保证这些小星星通过细线可以串在一起。
n<=17,m<=n*(n-1)/2

Output

输出共1行,包含一个整数表示可能的对应方式的数量。
如果不存在可行的对应方式则输出0。

Sample Input

4 3
1 2
1 3
1 4
4 1
4 2
4 3

Sample Output

6

HINT

Source

Solution

一道容斥的好题

我们一共要满足两个限制:1.树中的一个点对应图中一个点,且一一对应  2.树中两点有边的,图中两点也对应有边

首先我们考虑最暴力的方法,如果同时满足两个限制,用$O(N^{N})$的时间去枚举,然后计数

那如果我们放宽一个限制,只统计满足限制2的数目,这显然可以用树形DP在$O(N^{3})$的时间里得到的

这里得到的是有$K$个点可以映射,但不保证$K$个点都被映射到,且不保证每个点只被映射一次

那么考虑用容斥去统计出答案,答案就是$Ans(N)-Ans(N-1)+Ans(N-2)-Ans(N-3)+Ans(N-4).....$

这样容斥的时候的枚举是$O(2^{N})$的

所以总的复杂度是$O(2^{N}×N^{3})$的

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define LL long long
#define MAXN 50
int N,M;
struct EdgeNode{int next,to;}edge[MAXN<<];
int head[MAXN],cnt=;
void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
LL dp[MAXN][MAXN],ans,now,tmp;
int lt[MAXN][MAXN],bin[MAXN],tot,a[MAXN];
void DFS(int now,int last)
{
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last) DFS(edge[i].to,now);
for (int i=; i<=tot; i++)
{
dp[now][i]=;
for (int j=head[now]; j; j=edge[j].next)
if (edge[j].to!=last)
{
tmp=;
for (int k=; k<=tot; k++)
if (lt[a[k]][a[i]]) tmp+=dp[edge[j].to][k];
dp[now][i]*=tmp;
}
}
}
int main()
{
N=read(),M=read();
for (int x,y,i=; i<=M; i++) x=read(),y=read(),lt[x][y]=lt[y][x]=;
for (int x,y,i=; i<=N-; i++) x=read(),y=read(),InsertEdge(x,y);
bin[]=; for (int i=; i<=N; i++) bin[i]=bin[i-]<<;
for (int i=; i<=bin[N]-; i++)
{
now=; tot=;
for (int j=; j<=N; j++) if (i&bin[j-]) a[++tot]=j;
DFS(,);
for (int j=; j<=tot; j++) now+=dp[][j];
if ((tot&)==(N&)) ans+=now; else ans-=now;
}
printf("%lld\n",ans);
return ;
}

最新文章

  1. python正则表达式re
  2. 浅谈JS之AJAX
  3. 织梦系统dedecms如何开启伪静态
  4. JSOI Round 2题解
  5. 查看Android应用包名package和入口activity名称
  6. Ubuntu Qt arm-linux-androideabi-gcc: Command not found
  7. nginx 重启命令
  8. 通过 Chrome 在 Windows 中调试运行在 iphone-safari 上的 页面
  9. 解决MySQL在修改列时因为外键依赖出错的问题
  10. PDF怎样添加注释,PDF文件添加注释的方法
  11. 3D Math Keynote 2
  12. JavaScript的内置对象(Math对象)
  13. RxSwift学习笔记10:startWith/merge/zip/combineLatest/withLatestFrom/switchLatest
  14. JAVA 线程池架构浅析
  15. lumisoft.net 邮件管理系列文章 - 如何判断附件为内嵌式还是附加式
  16. 采用太平洋AI集装箱箱号识别接口实现集装箱箱号识别
  17. char* 与 char[] 的区别
  18. Yii2 环境配置生产环境和测试环境
  19. Linux 和 Windows 之间共享文件之 samba
  20. AsyncTask 和 Thread 区别

热门文章

  1. tomcat 启动参数 Xms, Xmx, XX:MaxNewSize, XX:PermSize, -XX:MaxPermSize, Djava.awt.headless
  2. PAT 1013. 数素数 (20)
  3. AAL模版 中英文对照
  4. MIPAV - Talairach ACPC transform
  5. Java Web开发Tomcat中三种部署项目的方法
  6. MVC中如何设置路由指定默认页
  7. Generate Parentheses
  8. 清北学堂2017NOIP冬令营入学测试P4749 C’s problem(c)
  9. caffe的python接口学习(3):训练模型(training)
  10. 浅谈JS继承