您的位置:首页 > 产品设计 > UI/UE

UVALive 5002/ lightoj 1382 The Queue(树形DP)

2017-04-03 21:30 411 查看
题意:有n个人,除BOSS外,每个人都有一个上司,现在要排队,每个人都不能排在自己的上司前面,问有几种排法。

思路参考大神的吧:

首先求出以每个结点为根的子树大小,记为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)预处理出来。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int maxn = 1e3+5;
ll dp[maxn], cnt[maxn], C[maxn][maxn];
bool book[maxn];
vector<int> g[maxn];

void init()
{
for(int i = 0; i < maxn; i++)
{
C[i][0] = C[i][i] = 1;
for(int j = 1; j < i; j++)
C[i][j] = (C[i-1][j-1]+C[i-1][j])%mod;
}
}

void dfs(int u)
{
dp[u] = 1;
for(int i = 0; i < g[u].size(); i++)
{
int v = g[u][i];
dfs(v);
cnt[u] += cnt[v];
dp[u] = (dp[u]*C[cnt[u]][cnt[v]])%mod*dp[v]%mod;
}
cnt[u]++; //加上根这个点
}

int main(void)
{
init();
int t, n, ca = 1;
cin >> t;
while(t--)
{
for(int i = 0; i < maxn; i++)
g[i].clear();
memset(book, 0, sizeof(book));
memset(cnt, 0, sizeof(cnt));
scanf("%d", &n);
for(int i = 2; i <= n; i++)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
book[v] = 1;
}
int r;
for(int i = 1; i <= n; i++)
if(!book[i])
{
r = i;
dfs(i);
break;
}
printf("Case %d: %lld\n", ca++, dp[r]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  lightoj DP