题意:n个人排队,每个人b除CEO外都有一个监督人a,b必须排在a的后面,问有多少排队方案。
解析:显然是一个树形DP,简单想想子树的合并后的方案数怎么算就好了,挺简单的题。
设dp[i]为以i为根的子树中对应的方案数,num[i]是以i为根的子树的节点数。
下面考虑将两个队伍v1,v2合并一个队伍。
其对应的方案数为C(num[v1]+num[v2],num[v1])*dp[v1]*dp[v2]。
依据这个进行dfs。
[code]:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL MOD = 1e9+7;
struct Nod{
int b,next;
void init(int b,int next){
this->b=b;this->next=next;
}
}buf[2005];
LL C[2005][2005],Mul[2005],dp[1005];
int n,len,E[1005],num[1005],deg[1005],root;
void init(){
len = 0;
memset(E,-1,n*sizeof(int));
memset(deg,0,n*sizeof(int));
}
void addEdge(int a,int b){
buf[len].init(b,E[a]);E[a]=len++;
buf[len].init(a,E[b]);E[b]=len++;
}
void dfs(int u,int pre){
int i,v;
dp[u] = 1;num[u] = 1;
for(i = E[u];i != -1;i = buf[i].next){
v = buf[i].b;
if(v == pre) continue;
dfs(v,u);
num[u] += num[v];
dp[u] = C[num[u]-1][num[v]]*dp[u]%MOD*dp[v]%MOD;
}
}
int main(){
int i,j,cas,T;
Mul[0] = C[0][0] = 1;
for(i = 1;i <= 2000;i++){
Mul[i] = (i*Mul[i-1])%MOD;
C[i][0] = C[i][i] = 1;
for(j = 1;j < i;j++)
C[i][j] = (C[i-1][j]+C[i-1][j-1])%MOD;
}
scanf("%d",&cas);
for(T = 1;T <= cas;T++){
scanf("%d",&n);
init();
int u,v;
for(i = 1;i < n;i++){
scanf("%d%d",&u,&v);u--,v--;
addEdge(u,v);
deg[v]++;
}
for(i = 0;i < n;i++)
if(!deg[i]) root = i;
dfs(root,-1);
printf("Case %d: %lld\n",T,dp[root]);
}
return 0;
}