UVa 1362(LA 3516) Exploring Pyramids

依旧是《训练指南》上的一道例题。思路大致相同,即设有一个序列S(i),S(i+1),S(i+2)...S(j),d[i,j]为所求的解。当S(i)==S(k),i<k<=j 时,说明在k回到根,那么S(i+1)...S(k-1)构成一棵独立的子树(当然也可能并不是子树)。那么d[i,j]就要加上d[i+1,k-1]*d[k,j],不断递增k,每遇到一个k,d[i,j]+=d[i+1,k-1]*d[k,j]直到k>j。最后的d[i,j]就是序列S(i)..S(j)的解。那么题目最终的解即为d[0,n-1],n为序列的长度。

不过,在具体的解法上,我和书上的做法不一样。书上使用的是递归,而我使用了从底向下的方法。显然d[i,i]=1,然后采用类似于最优二叉排序树的解法,依次求出j-i=1,j-i=2....j-i=n-1时的d[i,j]的值。最后输出d[0,n-1]即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#define MAX 300+5
#define MOD 1000000000
using namespace std;

long long ans[MAX][MAX];

int main()
{
    string S;
    while(cin>>S){
        int n=S.size();
        memset(ans,0,sizeof(ans));
        for(int i=0;i<n;++i) ans[i][i]=1;//单个节点的树都为一种情况

        for(int i=1;i<n;++i){//两个坐标间的差值
            for(int j=0;j+i<n;++j){
                for(int k=1;k<=i;++k){//从j+1遍历到j+i
                    if(S[j]==S[j+k]){
                        ans[j][j+i]+=ans[j+1][j+k-1]*ans[j+k][j+i];
                        ans[j][j+i]%=MOD;
                    }
                }
            }
        }

        cout<<ans[0][n-1]<<endl;
    }

    return 0;
}
时间: 2024-12-28 11:38:36

UVa 1362(LA 3516) Exploring Pyramids的相关文章

uva live 3516 Exploring Pyramids 区间DP

// uva live 3516 Exploring Pyramids 区间DP // // 题目大意: // // 给你一个多叉树,每个节点是一个大写字母,从根节点走,按照先序遍历的 // 原则访问,不能访问则回溯,每次记录一下节点的字符,最后得到一个字符串.现 // 在给你一个字符串,问可能符合条件的多叉树的数量. // // 解题思路: // // 区间DP,我们注意到,从根节点出发,一定会再次回到根节点,那么我们可以设 // d(i,j) 是序列i到j段形成的符合条件的多叉树的数量,则

【区间dp】【记忆化搜索】UVALive - 3516 - Exploring Pyramids

f(i,j)=sum(f(i+1,k-1)*f(k,j) | i+2<=k<=j,Si=Sk=Sj). f(i+1,k-1)是划分出第一颗子树,f(k,j)是划分出剩下的子树. #include<cstdio> #include<cstring> using namespace std; typedef long long ll; #define MOD 1000000000ll char s[310]; ll f[310][310]; int n; ll dp(int

UVALive 3516 Exploring Pyramids (区间dp)

#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; #define ll long long const int maxn = 310; const ll mod = 1e9; char s[maxn]; ll dp[maxn][maxn]; ll solve(int i, int j) { if(i == j) retu

UVALive 3516 Exploring Pyramids 区间dp+计数原理

题目链接:点击打开链接 给定多叉树的先序遍历结果,求多叉树的同构数 思路:区间dp import java.io.PrintWriter; import java.util.ArrayList; import java.util.Scanner; public class Main { int min(int a,int b){return a>b?b:a;} int max(int a,int b){return a>b?a:b;} long min(long a,long b){retur

UVA 1362 - Exploring Pyramids(计数问题+区间DP)

题目链接:1362 - Exploring Pyramids 白书上的例题,思路是对于每个结点,往后遍历分为左右两边子树来考虑,左边的子树为去掉根节点剩下的子树,而右边是要算上根节点的,这样就不会有重复的情况出现,然后根据乘法原理,左右两边情况相乘为总情况数,然后计算这些总和. f[i][j]表示[i,j]结点的情况种数,那么 f[i][j] = sum{f[i + 1][k - 1] * f[k][j]},并且s[i] == s[k] == s[j],因为i, j, k表示的是根节点必须相同.

UVA 1362 Exploring Pyramids 区间DP

Archaeologists have discovered a new set of hidden caves in one of the Egyptian pyramids. The decryption of ancient hieroglyphs on the walls nearby showed that the caves structure is as follows. There are n caves in a pyramid, connected by narrow pas

UVALive - 3516【多叉树遍历Exploring Pyramids】-----2015年1月27日

一:问题描述 本题题意大致是说:给出一棵多叉树,每个节点的任意两个子节点都有左右之分.从根节点开始,每次尽量往左边走.走不通了就回溯,把遇到的字母顺次记录下来,可以得到一个序列.现在给定一个序列,要求满足条件的多叉树的数目. 二:题目分析 我们可以分析对于这个序列而言一定是对称序列,那么对于序列S而言, 我们定义d(i,j)为子序列对应的树的个数,边界条件是: 并且我们可以得出如下结论: 在其它情况下,设第一个分支在Sk 时回到树根(必须有Si =Sj )则这个分支对应的序列是 ,方案数为:d(

uva 1356/LA 3485 Bridge 题解

题意:有一座桥,桥上等距摆若干个塔,高度H,宽度不计.相邻两个塔距离不超过D.有一个绳索,总长度为L,桥的长度为L,两个塔之间的绳索成全等的抛物线.求建最少的塔的时候绳索下端离地高度y. 白书上的例题..我基本上是抄的代码. 间隔数n=ceil(B/D),每个间隔宽度D'=B/n,之间的绳索长度L'=L/n.则抛物线的宽度已知,即D'. 根据微积分知识,可导函数f(x)在区间[a,b]上的弧长为\(\int_{b}^{a} \sqrt{1+[f'(x)]^2}dx\) . 则此时抛物线的长度只与

《算法竞赛入门经典——训练指南》第二章题库

UVa特别题库 UVa网站专门为本书设立的分类题库配合,方便读者提交: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=442 注意,下面注有"extra"的习题并没有在书中出现,但在上面的特别题库中有,属于附加习题. 基础练习 (Basic Problems) UVa11388 GCD LCM UVa11889 Benefit UVa10943 How do y