HDU 5379 Mahjong tree(树的遍历&组合数学)

本文纯属原创,转载请注明出处。谢谢。

http://blog.csdn.net/zip_fan

题目传送门:http://acm.hdu.edu.cn/showproblem.php?

pid=5379

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

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

题意:在一颗树上有n个节点,如今要把他们进行1-n编号。

要保证1、兄弟节点之间号是连续的,2、每棵子树号自身是连续的,求一共同拥有多少种可能。

事实上很easy,首先兄弟节点之间号是连续的,并且子树号是连续的,那么互为兄弟节点的那些点中。至多有2个节点有儿子节点,否则不可能满足上述条件。

仅仅要明确了这一点,直接遍历树。统计就可以。

可是题目有一个很大的神坑点:给边的时候是任意的,所以必须先双向建图。然后从根节点開始遍历一遍,把多余的边删掉。(比赛的时候被坑了好久)

当然hdu的栈深度就不吐槽了,手动开栈。c++提交。

以下上代码。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <map>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#define moo 1000000007//10^9+7
#define PI acos(-1.0)
#define eps 1e-5
#pragma comment (linker,"/STACK:102400000,102400000")
using namespace std;
long long jie[100000+100];//存阶乘。即全排列情况
vector<int>tre[100000+100];//存点i能到的点,相当于邻接表建图。
int vis[100000+100];//存第i个点的訪问情况
void init()
{
    jie[0]=1;
    for(int i=1;i<=100000;i++)
    {
        jie[i]=jie[i-1]*i;
        jie[i]%=moo;
    }
}//n个无子节点的兄弟节点能够有n!种排列
void dfs1(int num)//先遍历一遍树,将多余的边删除
{
    vis[num]=1;
    int nn=tre[num].size();
    int now=0;
    while(now<nn)
    {
        if(vis[tre[num][now]]==1)
        {
            tre[num].erase(tre[num].begin()+now);
            nn--;
            continue;
        }
        dfs1(tre[num][now]);
        now++;
    }
}
long long dfs(int num,int has)//统计num节点的情况,has代表num是否有兄弟节点
{
    if(tre[num].size()==0)//假设num没有子节点,直接return 1。表示仅仅有1种排列情况
        return 1;
    long long ans=1;
    int num1=0;//存num点的子节点中无子节点的节点个数
    int num2=0;//存num点的子节点中有子节点的节点个数
    int nn=tre[num].size();
    for(int i=0;i<nn;i++)
    {
        if(tre[tre[num][i]].size()==0)
            num1++;
        else
            num2++;
    }
    if(num2>2)
        return 0;//假设有超过2个点有子节点。那么一定无法满足条件。return 0
    if(has==0)//假设num点没有兄弟节点,那么num点能够在子节点的最左或者最右,即2种选择
        ans*=2;
    ans*=jie[num1];//num的子节点中无子节点的节点能够组成全排列
    ans%=moo;
    if(num2==0)//假设没有有子节点的节点。那么该点统计完成
        return ans;
    if(tre[num].size()!=1)//假设不止有一个有子节点的子节点。那么该子节点能够在最左或最右
        ans*=2;
    int go;
    if(tre[num].size()==1)//推断其子节点是否有兄弟节点,为其子节点的统计做准备
        go=0;
    else
        go=1;
    for(int i=0;i<nn;i++)
    {
        if(tre[tre[num][i]].size()!=0)
        {
            long long la=ans;
            ans*=dfs(tre[num][i],go);//假设该点有子节点,继续统计
            ans%=moo;
        }
    }
    return ans%moo;
}
int main()
{
    int T;
    cin>>T;
    int dd=T;
    init();
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            tre[i].clear();
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n-1;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            tre[y].push_back(x);
            tre[x].push_back(y);
        }
        dfs1(1);
        printf("Case #%d: %I64d\n",dd-T,dfs(1,0));
    }
    return 0;
}
时间: 2024-08-10 11:27:41

HDU 5379 Mahjong tree(树的遍历&amp;组合数学)的相关文章

Hdu 5379 Mahjong tree (dfs + 组合数)

题目链接: Hdu 5379 Mahjong tree 题目描述: 给出一个有n个节点的树,以节点1为根节点.问在满足兄弟节点连续 以及 子树包含节点连续 的条件下,有多少种编号方案给树上的n个点编号? 解题思路: 对于一个节点来讲,非叶子儿子节点最多有两个才能满足要求,否则满足子树节点连续的话就无法满足兄弟节点连续.然后有dfs计算每棵子树的贡献值,每棵子树的子节点可以分为叶子节点X和非叶子节点Y,叶子节点可以分配到一组连续的编号,非叶子节点只能分配到兄弟节点中最大或者最小编号两种情况,叶子节

hdu 5379 Mahjong tree(树形dp)

题目链接:hdu 5379 Mahjong tree 树形dp,每个节点最多有2个子节点为一棵节点数大于1的子树的根节点,而且要么后代的节点值都大于,要么都小于本身(所以tson不为0是,要乘2).对于K个单一节点的子节点,种类数即为全排K!.当一个节点没有兄弟节点时,以这个节点为根结点的子树,根可以选择最大或者最小. #pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #inclu

HDU 5379 Mahjong tree(dfs)

题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=5379 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 verte

HDU 5379 Mahjong tree (详解,构造+思维)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5379 题面: Mahjong tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1148    Accepted Submission(s): 351 Problem Description Little sun is an art

hdu 5379 Mahjong tree(构造)

题目: Mahjong tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1471    Accepted Submission(s): 448 Problem Description Little sun is an artist. Today he is playing mahjong alone. He suddenly

hdu 5379 Mahjong tree 树形DP入门

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

2015多校第7场 HDU 5379 Mahjong tree 构造,DFS

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5379 题意:一颗n个节点n-1条边的树,现在要给每个节点标号(1~n),要求:(1)每一层的兄弟节点的标号要是连续的(2)每一颗子树的所有节点标号是连续的.问有多少种标号方案. 解法:对于每一层顶多只能存在2个非叶子节点,否则无解:对于每一层有x个叶子节点,y个非叶子节点,那么ans=(ans * x!)%mod,另外如果y!=0,还得ans=2*ans%mod. #include <bits/st

hdu 5379 Mahjong tree 树形dp

链接 题意:给定一棵树 把1-n填到树的节点上,使得: 1:儿子节点上填的数字是连续的. 2:子树节点上填的数字是连续的. 把儿子节点分成两种,一种是叶子节点,一种是非叶子节点. 显然非叶子节点个数不能超过2个,不然就不存在这样的方案了. 然后分类讨论一下非叶子节点个数即可. #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstdio> #i

HDU 5379 Mahjong tree

题意:在一棵有n个节点的树上放编号从1到n的麻将,要求每个点的儿子节点之间的编号连续,每棵子树内的编号连续. 解法:手推一组样例之后就可以得到如下结论然后从根节点一边讨论一边搜就好了. 当一个节点只有一个儿子的时候,如果儿子是叶子节点则只有一种放法,如果儿子不是叶子节点则有两种放法. 当一个节点有两个儿子的时候,一定有两种放法. 当一个儿子有三个儿子及以上的时候,假设有k个儿子,如果非叶子节点m的个数为0则有k!种放法,如果m为1,则有2 × (k - 1)!种放法,如果m为2,则有2 × (k