UVa 10529 : Dumb Bones(期望DP)

传送门

题意:
你试图把一些多米诺骨牌排成直线,然后推倒它们。但是如果你在放骨牌的时候不小心把刚放的骨牌碰倒了,它就会把相临的一串骨牌全都碰倒,而你的工作也被部分的破坏了。比如你已经把骨牌摆成了DD__DxDDD_D的形状,而想要在x这个位置再放一块骨牌。它可能会把左边的一块骨牌或右边的三块骨牌碰倒,而你将不得不重新摆放这些骨牌。这种失误是无法避免的,但是你可以应用一种特殊的放骨牌方法来使骨牌更多的向一个方向 。
给定n,表示要放n个骨牌,每次放下骨牌,有可能向左倒的概率为pl,向右倒的概率为pr,如果倒下,会将那一侧的骨牌全部推倒,可以选择位置先后放骨牌,问说一种放骨牌次数最少的期望是多少?

题解:
考虑最后放好的多米诺骨牌:一定有一个位置是最后放上去的。对于这个位置两边的位置要放置好,其实是一个子问题,而且没有后效性,因为中间空了一格,左右不会互相影响。可以 DP 求解

现在考虑怎么转移,设 dp[i] 表示放置好长度为 i 的最小期望步数,那么对于长度i1的状态,可以枚举最后加入的牌,从两边转移。

关于转移方程,考虑加入最后一个骨牌,把它放置好的期望次数是 st=11LR ,其中期望 stL 次往左边倒, stR 次往右边倒,还要算上在加入这张牌之前的期望步数,那么得出转移:

dp[i]=minj=0i1{dp[j]+dp[ij1]+dp[j]stL+dp[ij1]stR+st}

时间复杂度 O(n2)
还有更优秀的做法,比如二分,决策单调性等等,可以参考论文

#include<bits/stdc++.h>
using namespace std;
const int Maxn=1e3+50;
int n;
double L,R,dp[Maxn];

int main(){
    while(scanf("%d",&n),n){
        scanf("%lf%lf",&L,&R);
        dp[0]=0,dp[1]=1.0/(1.0-L-R);
        for(int i=2;i<=n;i++){
            dp[i]=1e9;
            for(int j=0;j<i;j++){
                dp[i]=min(dp[i],(dp[j]*(1.0-R)+dp[i-j-1]*(1.0-L)+1.0)/(1.0-L-R));
            }
        }
        printf("%.2f\n",dp[n]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值