hdu 5379 Mahjong tree 2015多校联合训练赛#7 dfs

Mahjong tree

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 175    Accepted Submission(s): 51


Problem Description
Little sun is an artist. Today he is playing mahjong alone. He suddenly feels that the tree in the yard doesn't look good. So he wants to decorate the tree.(The tree has n vertexs, indexed from 1 to n.)
Thought for a long time, finally he decides to use the mahjong to decorate the tree.
His mahjong is strange because all of the mahjong tiles had a distinct index.(Little sun has only n mahjong tiles, and the mahjong tiles indexed from 1 to n.)
He put the mahjong tiles on the vertexs of the tree.
As is known to all, little sun is an artist. So he want to decorate the tree as beautiful as possible.
His decoration rules are as follows:

(1)Place exact one mahjong tile on each vertex.
(2)The mahjong tiles' index must be continues which are placed on the son vertexs of a vertex.
(3)The mahjong tiles' index must be continues which are placed on the vertexs of any subtrees.

Now he want to know that he can obtain how many different beautiful mahjong tree using these rules, because of the answer can be very large, you need output the answer modulo 1e9 + 7.
 

Input
The first line of the input is a single integer T, indicates the number of test cases. 
For each test case, the first line contains an integers n. (1 <= n <= 100000)
And the next n - 1 lines, each line contains two integers ui and vi, which describes an edge of the tree, and vertex 1 is the root of the tree.
 

Output
For each test case, output one line. The output format is "Case #x: ans"(without quotes), x is the case number, starting from 1.
 

Sample Input
  
  
2 9 2 1 3 1 4 3 5 3 6 2 7 4 8 7 9 3 8 2 1 3 1 4 3 5 1 6 4 7 5 8 4
 

Sample Output
  
  
Case #1: 32 Case #2: 16
 

Source

每个结点的孩子的id要连续,每个子树的id要连续。

因此每个结点的子树中,不能有超过两个规模大于1的子树。否则是无法安排的。

根据如此。给一个连续区间,子树的根的值由父亲决定。

在一个区间中,规模大于1的子树必然选择的是最左边或者最右边的连续的id值,

并且直接子节点id是左区间最大值,或者右区间最小值。剩下规模为1的子树,有N!种安排方法。

对于一棵子树分三种情况:

 在代码中讨论


#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define maxn 100007
vector<int>head[maxn];
vector<int>son[maxn];
ll size[maxn];
ll mod = 1000000007;
ll jie[maxn];

ll dfs(int u,int f){
    size[u] = 1;
    ll ans = 1;
    int son2 = 0,son1 = 0;
    for(int i = 0;i < head[u].size(); i++){
        int v = head[u][i];
        if(v == f) continue;

        ans = ans*dfs(v,u)%mod;
        if(ans == 0) return 0; //答案等于0,则无解直接返回

        if(size[v] > 1) son2++;
        else son1++;

        if(son2 > 2) return 0;

        size[u] += size[v];
    }
    if(son2 == 2 ){ //两个规模大于1的子树,可以安排他们在最左,最右的位置,两种
        ans = ans*2%mod;
    }
    else if( son2 == 1 && son1 > 0) //存在规模大于1的子树和只有1的子树,安排大子树使用在左边,或者右边的连续id
        ans = ans*2%mod;
    else if( son2 == 1 && son1 == 0 )//规模大于1的子树只有1个,那么该子树的根选最小值,最大值都可以。跟总根一样
        ans = ans*2%mod;

    ans = ans*jie[son1]%mod;

    return ans;
}
int main(){
    int t,n;
    scanf("%d",&t);
    jie[0] = 1;//处理阶乘的值
    for(int i = 1;i < maxn; i++){
        jie[i] = jie[i-1]*i%mod;
    }
    int tt = 1;
    while(t--){
        scanf("%d",&n);
        memset(size,0,sizeof(size));
        for(int i = 1;i <= n; i++)
            head[i].clear();
        int u,v;
        for(int i = 1;i < n; i++){
            scanf("%d%d",&u,&v);
            head[u].push_back(v);
            head[v].push_back(u);
        }
        ll ans = dfs(1,0);
        if(size[1] > 1) ans = ans*2%mod; //如果树的规模大于1,根可以选最小值,或者最大值的id
        printf("Case #%d: %I64d\n",tt++,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GDRetop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值