【算法学习笔记】75. 动态规划 棋盘型 期望计算 1390 畅畅的牙签盒(改)

一开始用了模拟的方法,DFS来搜索,但是因为当n很大的时候有很多的重复计算,因为会踏过重复的点进行重复的操作,而且不能不走这些重复的路径,因为没有存储结果,最后只过了三个点。

考虑到重复的路径,所以想到利用动态规划。

可以认为dp[i][j]表示的是 从左上角开始走,走出以(1,1)到(i,j)为两个端点的棋盘中拿到牙签袋的期望。

画图可以知道,因为每次都是斜向下走。走出 i,j棋盘,可以是先走出比这个棋盘小的36种小棋盘的任何一种,然后再吃到在小棋盘和i,j中的某一个,拿到的牙签期望。

(如果走出了一个小棋盘,还可以再出大棋盘之前吃两个的话,这种情况已经被在其他的小棋盘(比前面说的小棋盘大一点)算过了,所以不用考虑)

 

所以这样的话就是

dp[i][j] = E {(dp[i-t][j-k]+1) * 1 / 36} ; t,k从1到6 E表示求和

 

注意这里需要处理一下就是因为i-t和j-k有可能不存在,所以dp是0,但是这样会丢失分子的1,

所以先把36个36分之1从求和中拿出来。

得到最后的公式就是

dp[i][j] = E{ (dp[i-t][j-k]) * 1 / 36}  + 1;

代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;


double p = 1.0/36;
double dp[1000+10][1000+10];


int main(int argc, char const *argv[])
{

    //DP过程
    int n;
    cin>>n;
    //以此更新每个点
    for (int i = 1; i <=n; ++i){
        for (int j=1; j <=n; ++j){
            dp[i][j] = 0.0;
            //从36个小棋盘中跨越出来 
            for (int dx = 1; dx <=6 ; ++dx){
                    for (int dy=1; dy <= 6; ++dy){
                        if(i-dx>=1 and j-dy>=1)
                            dp[i][j] += dp[i-dx][j-dy]/36;
                    }
                }
            dp[i][j]+=1.0;
        }
    }
    printf("%.2f\n", dp[n][n] );

    return 0;
}

 

posted @ 2015-07-18 15:01  雨尘之林  阅读(577)  评论(0编辑  收藏  举报