括号

【问题描述】

有一个长度为n的括号序列,以及k种不同的括号。序列的每个位置上是哪种括号是随机的,并且已知每个位置上出现每种左右括号的概率。求整个序列是一个合法的括号序列的概率。

我们如下定义合法括号序列:

 空序列是合法括号序列;

 如果A合法括号序列,那么lAr是合法括号序列,当且仅当l和r是同种的左右括号;

 如果A和B是合法括号序列,那么AB是合法括号序列。

【输入格式】

输入第一行包含两个整数n和k。接下来的输入分为?组,每组?行。第?组第

?行包含两个实数?[?,?]和?[?,?],分别代表第?个位置上是第?类的左括号和右括号

的概率。

【输出格式】

输出一行,包含一个实数,代表序列是合法括号序列的概率。建议保留至少

5 位小数输出。只有当你的输出与标准答案之间的绝对误差不超过10 −5 时,才会

被判为正确。

【样例输入 1】

2 1

1.00000 0.00000

0.00000 1.00000

【样例输出 1】

1.00000

【样例输入 2】

4 1

0.50000 0.50000

1.00000 0.00000

0.00000 1.00000

0.50000 0.50000

【样例输出 2】

0.25000

【数据规模和约定】

对于20%的数据,? ≤ 50,? = 1,所有位置的概率非 0 即 1。

另外有 30%的数据,? ≤34,? = 1,前 10 个和后 10 个位置的所有概率都是 0.5,中间剩余位置的概率非 0 即 1。

80%的数据,?,? ≤ 50。

对于100%的数据,1 ≤ ? ≤ 200,1 ≤ ? ≤ 50。

/*
  暴力50分
  正解是DP,f[i][j]表示i-j符合要求且是题目中第一种情况的概率,g[i][j]是第二种情况的概率,这么些事为了防止当出现(……)(……)(……)的情况时,枚举断点时会重复数。枚举时只枚举前半段是第一种情况,后半段是第二种情况的。 
*/
#include<cstdio>
#define N 210
#define M 60
using namespace std;
double l[N][M],r[N][M],f[N][N],g[N][N];
int n,m;
int main(){
    freopen("brackets.in","r",stdin);
    freopen("brackets.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%lf%lf",&l[i][j],&r[i][j]);
        }
    }
    for(int i=0;i<n;i++)
       f[i+1][i]=1.0;
    for(int len=2;len<=n;len+=2){
        for(int i=1;i<=n-len+1;i++){
            for(int j=1;j<=m;j++)
                f[i][i+len-1]+=(f[i+1][i+len-2]+g[i+1][i+len-2])*l[i][j]*r[i+len-1][j];
            for(int j=i+1;j<=i+len-2;j+=2)
                g[i][i+len-1]+=f[i][j]*(f[j+1][i+len-1]+g[j+1][i+len-1]);
        }
    }
    printf("%.5lf",f[1][n]+g[1][n]);
    return 0;
}

 

posted @ 2016-11-13 21:27  karles~  阅读(297)  评论(0编辑  收藏  举报