【bzoj 4455】小星星(树型DP+容斥原理)

给一个n个点的图和一个n个点的树,求图和树上的点一一对应的方案数。(N<=17)
思路:
1.在树的结构上进行tree DP,f[i][j]表示树上点 i 对应图上点 j 时,这个点所在子树的方案数。O(n^3)。
2.我们可以发现如果按这个定义进行DP,“一一对应”的关系挺难保证。若枚举出全排列得到对应关系,这样就C(n,n)=n! 只能拿到暴力分;那么我们就不限制“一一对应”而改为“一对多”的关系进行tree DP,利用容斥原理达到O(2^n)的复杂度。(P.S.至于为什么用容斥原理我也不清楚,待我弄懂之后我会再更新的。)
3.这题的容斥原理应用是这样的:用二进制数枚举出每次DP有哪些数没有对应的树上的点,将所有情况下的DP方案数之和按求补集的公式来求就是“所有数都一一对应树上的点”的答案。

下图中圆圈1表示数1没有对应的点的方案数,依次类推。有颜色部分是我们要求的补集。

下面附上代码——

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 using namespace std;
  6
  7 typedef long long LL;
  8 const int N=20,M=400;
  9 struct node{int x,y,next;}a[2*N];
 10 int last[N],len;
 11 bool v[N][N],vis[N];
 12 LL f[N][N];
 13 int b[N],bt;
 14
 15 void add(int x,int y)
 16 {
 17     len++;
 18     a[len].x=x,a[len].y=y;
 19     a[len].next=last[x],last[x]=len;
 20 }
 21
 22 void dfs(int x,int fa)
 23 {
 24     /*for(int k=last[x];k;k=a[k].next)
 25     {
 26       int y=a[k].y;
 27       if(y==fa)continue;
 28       dfs(y,x);
 29     }
 30     for (int kk=1;kk<=bt;kk++)
 31     {
 32       int i=b[kk];
 33       f[x][i]=1;
 34       for (int k=last[x];k;k=a[k].next)
 35       {
 36         int y=a[k].y;
 37         if (y==fa) continue;
 38         LL h=0;
 39         for (int kkk=1;kkk<=bt;kkk++)
 40         {
 41           int j=b[kkk];
 42           if (v[i][j]) h+=f[y][j];
 43         }
 44         f[x][i]*=h;
 45       }
 46     }*///边建树,边不重复地DP
 47     if (vis[x]) return;
 48     for (int kk=1;kk<=bt;kk++)
 49     {
 50       int i=b[kk];
 51       f[x][i]=1;
 52       for (int k=last[x];k;k=a[k].next)
 53       {
 54         int y=a[k].y;
 55         if (y==fa) continue;
 56         dfs(y,x);
 57         vis[y]=true;
 58         LL h=0;
 59         for (int kkk=1;kkk<=bt;kkk++)
 60         {
 61           int j=b[kkk];
 62           if (v[i][j]) h+=f[y][j];
 63         }
 64         f[x][i]*=h;
 65       }
 66     }//打标记,快一点
 67 }
 68
 69 int main()
 70 {
 71     int n,m;
 72     scanf("%d%d",&n,&m);
 73     memset(v,false,sizeof(v));
 74     for (int i=1;i<=m;i++)
 75     {
 76       int x,y;
 77       scanf("%d%d",&x,&y);
 78       v[x][y]=v[y][x]=true;
 79     }
 80     memset(last,0,sizeof(last));
 81     len=0;
 82     for (int i=1;i<n;i++)
 83     {
 84       int x,y;
 85       scanf("%d%d",&x,&y);
 86       add(x,y),add(y,x);
 87     }
 88     LL ans=0;
 89     for (int i=1;i<(1<<n);i++)
 90     {
 91       bt=0;
 92       for (int j=1;j<=n;j++)
 93         if (i&(1<<(j-1))) b[++bt]=j;
 94       memset(vis,false,sizeof(vis));
 95       dfs(1,0);
 96       LL h=0;
 97       for (int j=1;j<=bt;j++)
 98         h+=f[1][b[j]];
 99       if ((n-bt)%2==0) ans+=h;//按补集
100       else ans-=h;
101     }
102     printf("%lld\n",ans);
103     return 0;
104 }
时间: 2024-10-10 20:18:52

【bzoj 4455】小星星(树型DP+容斥原理)的相关文章

HDU1561 The more, The Better(树型DP)

题目是有n个存有宝藏的城堡,攻克任何一个城堡都需要先攻克0个或其他1个城堡,问攻克m个城堡最多能得到多少宝藏. 题目给的城堡形成一个森林,添加一个超级根把森林连在一起就是树了,那么就考虑用树型DP: dp[u][m]表示以u结点为根的子树攻克m个结点的最大价值 但是这样转移太难了,根是从每个孩子通过各自分配若干的城堡去攻克转移的,一个排列组合数,阶乘,是指数级的时间复杂度! 看了题解,原来这是依赖背包,没看背包九讲..不过网上的博客似乎没说清楚,事实上这个状态应该是三个维度来表示: dp[u][

POJ3659 Cell Phone Network(树上最小支配集:树型DP)

题目求一棵树的最小支配数. 支配集,即把图的点分成两个集合,所有非支配集内的点都和支配集内的某一点相邻. 听说即使是二分图,最小支配集的求解也是还没多项式算法的.而树上求最小支配集树型DP就OK了. 树上的每个结点作为其子树的根可以有三个状态: 不属于支配集且还没被支配 不属于支配集但被其孩子支配 属于支配集 那么就是用dp[u][1\2\3]来表示动归的状态. 123转移该怎么转移就怎么转移..最后的结果就是min(dp[root][2],dp[root][3]). 要注意的是对于有些结点前2

HDU_1561_The more, The Better_树型dp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1561 The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7031    Accepted Submission(s): 4121 Problem Description ACboy很喜欢玩一种战略游戏,

HDU_1520_Anniversary party_树型dp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520 Anniversary party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 8233    Accepted Submission(s): 3574 Problem Description There is going to b

二叉苹果树(树型DP+背包)

二叉苹果树 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点).这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置.下面是一颗有4个树枝的树: 2   5 \  / 3  4 \  / 1 现在这颗树枝条太多了,需要剪枝.但是一些树枝上长有苹果. 给定需要保留的树枝数量,求出最多能留住多少苹果. 程序名:apple 输入格式: 第1行2个数,N和Q(1<=Q<= N,1<N<=

HDU_1011_Starship Troopers_树型dp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1011 Starship Troopers Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 16276    Accepted Submission(s): 4335 Problem Description You, the leader o

【HDOJ 5834】Magic boy Bi Luo with his excited tree(树型DP)

[HDOJ 5834]Magic boy Bi Luo with his excited tree(树型DP) Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description Bi Luo is a magic boy, he also has a migic tree,

【POJ 2486】 Apple Tree(树型dp)

[POJ 2486] Apple Tree(树型dp) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8981   Accepted: 2990 Description Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each

[HAOI2010][BZOJ2427] 软件安装|tarjan|树型dp

2427: [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 463  Solved: 194[Submit][Status][Discuss] Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(