zoukankan      html  css  js  c++  java
  • [置顶] 准备复赛

    【问题描述】

    今年的 NOIP 初赛真是简单,小可可不用吹灰之力就考进了复赛,但是复赛可没有
    那么简单了,小可可想要好好准备复赛,争取复赛拿个省一。今天小可可在复习树和图
    的最大匹配时就碰到这样的一个难题:n 个节点满足以下性质的不同的树有多少种。
    1、树是有标号的,每个节点被标上 1 到 n 之间的整数;
    2、每个节点最多和其他 3 个节点相连,但是 1 号节点最多和其他 2 个节点相连;
    3、这棵树的最大匹配(把树看成二分图后的最大匹配)数为 k。
    两棵树被认为不同当且仅当存在两个点 u、v,在一棵树中 u、v 之间有边,另一棵
    树中 u、v 之间没边。
    由于答案可能很大,所以小可可让你输出答案模 1000000007 (10 9 + 7)。

    【输入格式】

    第一行包含两个正整数 n,k。

    【输出格式】

    包含一行,为方案数。

    【样例】

    exam.in
    4 2
    exam.out
    12

    【数据范围】

    对于30%的数据,2≤n≤5;
    对于60%的数据,2≤n≤20;
    对于 100%的数据,2≤n≤50。

    【题解】

    算法一:
    可以枚举所有情况
    时间复杂度 O(……)
    期望得分:30 分。
    算法二:
    我们可以用动态规划来解决这个问题,我们知道算树的最大匹配可以用 dp,
    设状态为 dp[v][used](v 表示节点编号,used 表示 v 这个点是否被匹配)。而这
    里我们设这道题的状态为 f[n][dp0][dp1]表示有 n 个节点满足条件的有根树的个
    数,其中 dp0=dp[root][0],dp1=dp[root][1],转移时我们枚举 i 作为一个子树的大
    小,和两个子树的 dp0 和 dp1 值,记一个为 m0,m1,另一个记为 n0,n1,则可
    dp0
    推 知全树的和dp1值为s0=max(m0,m1)+max(n0,n1) ,s1=max(m0+n1,m1+n0,m0+n0)+1。
    dp[n][s0][s1]=Σdp [i][m0][m1]*dp[n-i-1][n0][n1]
    然后暴力实现。
    时间复杂度 O ( n 6 )
    期望得分:60 分。
    算法三:
    在算法二的基础上,我们可以发现如果是最大匹配 dp0 和 dp1 相差不会超过
    1,所以,我们可以将状态压缩成 f[n][dp0][dif],dif 表示 dp1 与 dp0 的差值。
    时间复杂度 O ( n 4 )
    期望得分:100 分。

    考试的时候我连二分图最大匹配都不知道。

    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <cmath>
    #include <ctime>
    #include <algorithm>
    #include <vector>
    #include <set>
    #include <queue>
    #include <map>
    #include <bitset>
    using namespace std;
    typedef long long ll;
    ll geti(){
        ll ret=0;char ch=getchar(),k=1;
        while((ch<'0' || ch>'9') && ch!='-')ch=getchar();
        if(ch=='-')k=0,ch=getchar();
        while(ch>='0' && ch<='9')ret=ret*10+ch-'0',ch=getchar();
        return k?ret:-ret;
    }
    const int N = 100;
    const int mo = 1e9 + 7;
    int n,k;
    ll f[N][N],g[N][N],c[N][N],inv2;
    ll ksm (ll a, ll b){
        ll ret = 1;
        while(b) {
            if(b&1) ret = ret*a%mo;
            a = a*a%mo; b>>=1;
        }
        return ret;
    }
    int main(){
        freopen("exam.in","r",stdin);
        freopen("exam.out","w",stdout);
        n=geti(); k=geti();
        for(int i=0;i<=n;i+=1) {
            c[i][0] = 1;
            for(int j=1;j<=i;j+=1) {
                c[i][j] = (c[i-1][j] + c[i-1][j-1]) % mo;
            }
        }
        g[0][0]=1;// f[1][0]=1;
        inv2 = ksm(2,mo-2);
        for(int i=1;i<=n;i+=1) {
            for(int j=0;j<=i/2;j+=1) {
                for(int k=0;k<=(i-1)/2;k+=1) {
                    for(int s=0;s<=j;s+=1) {
                        int a = (k!=0?k:1);
                        int b = ((i-1-k)!=0?(i-1-k):1);
                        if(k!=i-1-k || k==0) {
                            f[i][j] += g[k][s]*g[i-1-k][j-s]%mo*a%mo*b%mo*c[i-1][k]%mo;
                        } else {
                            f[i][j] += g[k][s]*g[i-1-k][j-s]%mo*a%mo*b%mo*c[i-1][k]%mo*inv2%mo;
                        }
                        f[i][j] %= mo;
                        if(j-1-s>=0) {
                            if(k!=i-1-k){
                                g[i][j] +=
                                    f[k][s]*g[i-1-k][j-1-s]%mo*a%mo*b%mo*c[i-1][k]%mo+
                                    g[k][s]*f[i-1-k][j-1-s]%mo*a%mo*b%mo*c[i-1][k]%mo+
                                    f[k][s]*f[i-1-k][j-1-s]%mo*a%mo*b%mo*c[i-1][k]%mo;
                                g[i][j] %= mo;
                            } else {
                                g[i][j] +=
                                    (
                                     f[k][s]*g[i-1-k][j-1-s]%mo*a%mo*b%mo*c[i-1][k]%mo+
                                     g[k][s]*f[i-1-k][j-1-s]%mo*a%mo*b%mo*c[i-1][k]%mo+
                                     f[k][s]*f[i-1-k][j-1-s]%mo*a%mo*b%mo*c[i-1][k]%mo
                                     )*inv2%mo;
                                g[i][j] %= mo;
                            }
    
                        }
                    }
                }
            }
        }
        cout << (f[n][k]+g[n][k])%mo;
        return 0;
    }
    
  • 相关阅读:
    Codeforces Round #485 (Div. 2) C题求三元组(思维)
    MongoDB设置访问权限、设置用户
    与MySQL交互(felixge/node-mysql)
    centos Supervisor
    Async详解之一:流程控制
    C# Socket连接请求超时机制
    tcp-client-c++
    C#TCPClient应用-一个简单的消息发送和接收
    centos下各种c++库文件的安装
    AngularJS与RequireJS集成方案
  • 原文地址:https://www.cnblogs.com/yanshannan/p/7413154.html
Copyright © 2011-2022 走看看