zoukankan      html  css  js  c++  java
  • Codeforces 509F Progress Monitoring:区间dp【根据遍历顺序求树的方案数】

    题目链接:http://codeforces.com/problemset/problem/509/F

    题意:

      告诉你遍历一棵树的方法,以及遍历节点的顺序a[i],长度为n。

      问你这棵树有多少种可能的形态。

      遍历方法:

        used[1 ... n] = {0, ..., 0};

        procedure dfs(v):

          print v;

          used[v] = 1;

          for i = 1, 2, ..., n:

            if (a[v][i] == 1 and used[i] == 0):

              dfs(i);

        dfs(1);

    题解:

      表示状态:

        dp[i][j] = numbers

        表示a[i to j]这些节点,以a[i]为根所能构成的树的方案数。

      找出答案:

        ans = dp[1][n]

      如何转移:

        dp[i][j]一定以a[i]为根,且第一个访问的子节点一定是a[i+1]。

        所以将dp[i][j]分为三部分:

          (1)根节点a[i]

          (2)最左边的一棵子树a[i+1 to k]

          (3)右边剩下的一堆节点a[k+1 to j]

        那么根据乘法原理:

          dp[i][j] = ∑ dp[i+1][k]*右边一堆节点的方案数

        然而遍历是根据节点编号从小到大访问儿子节点的。

        这就要求,对于后面的一堆节点,如果其中某一个a[x]要和a[i+1]在同一层,那么一定要有a[i+1]<a[x]。

        又因为对于右边的一堆节点来说,最先访问到的肯定是a[k+1]。

        所以就是要保证:a[i+1]<a[k+1] or a[k+1]不存在

        这样就不用管后面的节点了,爱咋分咋分……

        接下来考虑如何求右边一堆节点的方案数。

        a[k+1 to j]形成森林的方法数 = a[k to j]以a[k]为根的子树的方法数。

        所以右边一堆节点的方案数 = dp[k][j]

        最终就是:

          if(a[i+1]<a[k+1] || k==j)

            dp[i][j] += dfs(i+1,k)*dfs(k,j);

          用记忆搜搞就行。

      边界条件:

        dp[i][i] = 1

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define MAX_N 505
     5 #define MOD 1000000007
     6 
     7 using namespace std;
     8 
     9 int n;
    10 int a[MAX_N];
    11 long long dp[MAX_N][MAX_N];
    12 
    13 long long dfs(int i,int j)
    14 {
    15     if(i==j) return 1;
    16     if(dp[i][j]!=-1) return dp[i][j];
    17     dp[i][j]=0;
    18     for(long long k=i+1;k<=j;k++)
    19     {
    20         if(a[i+1]<a[k+1] || k==j)
    21         {
    22             dp[i][j]+=dfs(i+1,k)*dfs(k,j);
    23             dp[i][j]%=MOD;
    24         }
    25     }
    26     return dp[i][j];
    27 }
    28 
    29 int main()
    30 {
    31     cin>>n;
    32     for(int i=1;i<=n;i++) cin>>a[i];
    33     memset(dp,-1,sizeof(dp));
    34     cout<<dfs(1,n)<<endl;
    35 }
  • 相关阅读:
    DBImport v3.44 中文版发布:数据库数据互导及文档生成工具(IT人员必备)
    IT人生知识分享:博弈论的理性思维
    IT人生知识分享:概率与运气
    开源:秋式广告杀手源码
    浅说秋色园域名被国家互联网应急中心封与解的过程
    自定义可视化调试工具(Microsoft.VisualStudio.DebuggerVisualizers)
    Excel导入导出的业务进化场景及组件化的设计方案(上)
    回忆录:30岁那年,你成长了吗?(上篇)
    Excel导入导出组件的设计
    DBImport v3.3 中文版发布:数据库数据互导及文档生成工具(IT人员必备)
  • 原文地址:https://www.cnblogs.com/Leohh/p/8206941.html
Copyright © 2011-2022 走看看