您的位置:首页 > 其它

HDU 5379 树形DP Mahjong tree

2015-08-14 14:28 211 查看
任意一棵子树上节点的编号连续,每个节点的所有二字节点连续,求编号方案的总数。

稍微分析一下可知

每个节点的非叶子节点个数不能多于两个,否则这个子树无解,从而整棵树都无解。

每棵子树将所有节点按照编号从小到大排序,根节点要么在最左端,要么在最右端,而且这两种情况相等。(后面会有具体分析)

设size(u)表示以节点u为根的子树中节点总数。

d(u)表示用1 ~ size(u)给以u为根的子树编号的合法方案数,考虑下面几种情况:

①: u是叶子节点,方案数为1.

②: u的所有儿子节点都是叶子节点,那么所有儿子节点连续(假设儿子节点有S个),u只能放在所有儿子节点的前面或者最后面。所以方案数就是2(S!),因为儿子节点之间互不影响可以任意排列。

③: u只有一个非叶儿子节点v。

#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

typedef long long LL;

const int maxn = 100000 + 10;
const LL MOD = 1000000007;

vector<int> G[maxn];

int sz[maxn];
LL d[maxn], fac[maxn];

void dfs(int u, int fa)
{
sz[u] = 1;
LL T = 1;
int c1 = 0, c2 = 0;
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(v == fa) continue;
dfs(v, u);
sz[u] += sz[v];

if(d[v] == 0) { d[u] = 0; return ; }

if(sz[v] > 1) { c1++; T = (T * d[v]) % MOD; }
else c2++;

if(c1 > 2) { d[u] = 0; return ; }
}

if(sz[u] == 1) { d[u] = 1; return ; }
if(c1 < 2) d[u] = (2LL * fac[c2] * T) % MOD;
else d[u] = (fac[c2] * T) % MOD;
}

int main()
{
fac[0] = 1;
for(int i = 1; i < maxn; i++) fac[i] = (fac[i - 1] * i) % MOD;

int T; scanf("%d", &T);
for(int kase = 1; kase <= T; kase++)
{
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++) G[i].clear();
for(int i = 1; i < n; i++)
{
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}

printf("Case #%d: ", kase);

if(n == 1) { puts("1"); continue; }

dfs(1, 0);
printf("%I64d\n", d[1]);
}

return 0;
}


代码君
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: