LightOJ1382 The Queue(树型DP)

题目大概是说给一棵树的n个结点从1到n编号,要求每个结点的编号大于其父结点,问有多少种编号方式。

想了挺久的,感觉有点眉目,最后画了下样例YY出解法:

  • 首先求出以每个结点为根的子树大小,记为size[u],这个DFS一遍就可以求出来;
  • 接下来,dp[u]表示给以u为根的子树size[u]个编号有几种编号方案 
  • 然后考虑转移方程:
    • 比如一个结点u有3个儿子v1,v2,v3,那么u子树有size[u]个编号,编号最小的就属于u,剩下size[u]-1分配给u的三个子树,分配方式就有:

C(size[u]-1,size[v1])*C(size[u]-1-size[v1],size[v2])*C(size[u]-1-size[v1]-size[v2],size[v3])

    • 而v1、v2和v3子树对它们被分配的编号又分别有dp[v1]、dp[v2]和dp[v3]种编号方案,因此u子树的size[u]个编号总共的编号方式即dp[u]是:

dp[u] = dp[v1]*dp[v2]*dp[v3]*C(size[u]-1,size[v1])*C(size[u]-1-size[v1],size[v2])*C(size[u]-1-size[v1]-size[v2],size[v3])

于是就是这样用DP求解的。另外C(n,m)可以利用组合数的递推式C(n,m)=C(n-1,m)+C(n-1,m-1)预处理出来。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 struct Edge{
 6     int v,next;
 7 }edge[1111];
 8 int NE,head[1111];
 9 void addEdge(int u,int v){
10     edge[NE].v=v; edge[NE].next=head[u]; head[u]=NE++;
11 }
12 int n,size[1111];
13 long long C[1111][1111],d[1111];
14 int getSize(int u){
15     if(size[u]) return size[u];
16     int res=1;
17     for(int i=head[u]; i!=-1; i=edge[i].next){
18         int v=edge[i].v;
19         res+=getSize(v);
20     }
21     return size[u]=res;
22 }
23 long long dfs(int u){
24     if(d[u]) return d[u];
25     long long res=1;
26     int cnt=size[u]-1;
27     for(int i=head[u]; i!=-1; i=edge[i].next){
28         int v=edge[i].v;
29         res*=(dfs(v)*C[cnt][size[v]])%1000000007;
30         res%=1000000007;
31         cnt-=size[v];
32     }
33     return res;
34 }
35 int main(){
36     for(int i=0; i<1111; ++i) C[i][0]=1;
37     for(int i=1; i<1111; ++i){
38         for(int j=1; j<=i; ++j) C[i][j]=(C[i-1][j]+C[i-1][j-1])%1000000007;
39     }
40     int t,a,b;
41     scanf("%d",&t);
42     for(int cse=1; cse<=t; ++cse){
43         NE=0;
44         memset(head,-1,sizeof(head));
45         bool uroot[1111]={0};
46         scanf("%d",&n);
47         for(int i=1; i<n; ++i){
48             scanf("%d%d",&a,&b);
49             addEdge(a,b);
50             uroot[b]=1;
51         }
52         int root;
53         for(int i=1; i<=n; ++i){
54             if(!uroot[i]){
55                 root=i;
56                 break;
57             }
58         }
59         memset(size,0,sizeof(size));
60         getSize(root);
61         memset(d,0,sizeof(d));
62         printf("Case %d: %lld\n",cse,dfs(root));
63     }
64     return 0;
65 }
时间: 2024-12-25 19:04:27

LightOJ1382 The Queue(树型DP)的相关文章

【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

HDU 1520Anniversary party(树型DP)

HDU 1520   Anniversary party 题目是说有N个人参加party,每个人有一个rating值(可以理解为权值)和一个up(上司的编号),为了保证party的趣味性,每一个人不可以和他的直接上司都参加,问最后的rating和最大 这是一个典型的树形DP,DP[i][0]表示i不参加那他的这棵子树上的最大权值,DP[i][1]表示i参加时的这棵树上的最大权值,那么: DP[i][0] = sum{MAX(DP[j][1], DP[j][0])  |  j是i的直接子节点} D

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,

[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(