• 【HDOJ 5379】 Mahjong tree


    【HDOJ 5379】 Mahjong tree

    往一颗树上标号 要求同一父亲节点的节点们标号连续 同一子树的节点们标号连续 问一共同拥有几种标法

    画了一画 发现标号有二叉树的感觉
    初始标号1~n 根结点1能够标1或n 否则其它情况无法让以下的子树满足各自连续而且该根的儿子节点都要连续
    根结点下的节点平分其它标号 画一画能够发现 每一个根下最多有两颗子树 否则无法满足条件 而且两颗子树占领剩余标号的左右两边 中间夹的必须是叶子 这样才干满足该根下的儿子节点标号连续
    若根下仅仅有一颗子树 相同能够选择占剩余标号左部分/右部分
    剩余叶子全排列乘上就可以 每一个根都这样遍历一遍 假设期间出现一个根下有两颗以上的子树 就没法标号 即方案数为0 否则遍历完输出方案数就可以

    代码例如以下:

    #include <iostream>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #define ll long long
    #define MOD 1000000007
    
    using namespace std;
    
    ll a[100010]={1,1,2};//A(n,n)排列组合
    int n;
    vector<int> s[100010];
    bool vis[100010];
    
    ll bfs()
    {
        memset(vis,0,sizeof(vis));
        queue <int> q;
        q.push(1);
        vis[1] = 1;
        ll ans = 2;
        int i,u,v,yz,gen,sz;
        while(!q.empty())
        {
            u = q.front();
            q.pop();
            yz = gen = 0;
            sz = s[u].size();
            for(i = 0; i < sz; ++i)
            {
                v = s[u][i];
                if(vis[v]) continue;
                if(s[v].size() == 1)//当前节点为叶子节点(仅仅有v-u一条边)
                {
                    yz++;
                }
                else//为根结点
                {
                    gen++;
                    q.push(v);
                }
                vis[v] = 1;
            }
            if(gen > 2) return 0;//根结点超2 无解
            else if(gen)
            {
                ans = ((ans*2)%MOD*a[yz])%MOD;
            }
            else ans = (ans*a[yz])%MOD;
        }
        return ans;
    }
    
    int main()
    {
        for(int i=3;i<=100001;i++)
            a[i]=(a[i-1]*i)%MOD;
        int t,k=0;
        scanf("%d",&t);
        while(k++,t--)
        {
            scanf("%d",&n);
            memset(s,0,sizeof(s));
            int u,v;
            for(int i=1;i<n;i++)//双向建树
            {
                scanf("%d %d",&u,&v);
                s[u].push_back(v);
                s[v].push_back(u);
            }
            if(n == 1) printf("Case #%d: 1
    ",k);//特判仅仅有树根的情况
            else printf("Case #%d: %I64d
    ",k,bfs());
        }
    
        return 0;
    }
  • 相关阅读:
    Grid表格的js触发事件
    C# 在获得鼠标点击事件时,如何判断Control键,Shift键被按下
    纠错《COM技术内幕》之ProgID
    C# 日期格式化
    C# 操作系统防火墙
    C# 开发和调用Web Service
    谓侠
    高维FWT
    单位根反演
    容斥 反演
  • 原文地址:https://www.cnblogs.com/lytwajue/p/7267757.html
Copyright © 2020-2023  润新知