DP專題9 終 | 機器人 HDU -4576(概率DP)

本篇是一個概率DP問題,也是DP專題的最後一篇,概率DP是DP中一個較爲特殊的算法問題,混合了概率這個元素在裏面,需要對概率有比較好的理解。

 

概率DP問題很多時候會和複雜的概率計算混合在一起,要想更好的掌握只能多做相關題目,熟練掌握概率相關的知識也是很重要的一步。

概況DP是混合了概率計算和DP結構的一種算法。

本篇是一個入門題目,希望能夠讓沒接觸過概率DP的同學有個簡單瞭解。

 

Problem Description

Michael has a telecontrol robot. One day he put the robot on a loop with n cells. The cells are numbered from 1 to n clockwise.

麥克有一個遙控機器人,他把機器人放在一個圓盤上,圓盤分爲n格,如下圖所示,格子從1標記到n。
 



At first the robot is in cell 1. Then Michael uses a remote control to send m commands to the robot. A command will make the robot walk some distance. Unfortunately the direction part on the remote control is broken, so for every command the robot will chose a direction(clockwise or anticlockwise) randomly with equal possibility, and then walk w cells forward.

 

 

一開始機器人在格子1,麥克通過遙控給機器人發送m條指令。指令能夠讓機器人移動一段距離,機器人等概率的順時針或者逆時針進行移動,會向前移動w個格子。


Michael wants to know the possibility of the robot stopping in the cell that cell number >= l and <= r after m commands.

 

麥克想知道機器人停留在[l, r]區間的概率。

 

Input

There are multiple test cases. 
Each test case contains several lines.
The first line contains four integers: above mentioned n(1≤n≤200) ,m(0≤m≤1,000,000),l,r(1≤l≤r≤n).

 

第一行:格子數n,指令數m,區間l和r


Then m lines follow, each representing a command. A command is a integer w(1≤w≤100) representing the cell length the robot will walk for this command.  

 

接下來是m條指令,每條指令指的是機器人會移動m個格子。


The input end with n=0,m=0,l=0,r=0. You should not process this test case.

 

最後一行4個0表示結束

 

Output

For each test case in the input, you should output a line with the expected possibility. Output should be round to 4 digits after decimal points.

 

 

Sample Input


 

3 1 1 2
1
5 2 4 4
1
2
0 0 0 0

 

Sample Output


 

0.5000
0.2500

 

這是一個比較簡單的概率DP題目,只需要注意幾個點就能很快寫出代碼。

如下圖中的位置1,位置1的概率爲1.0,如果第一步走1格,則對於節點2來說,可能有1號位置和3號位置能夠到達2,到達2的概率即爲p(1)*0.5+p(3)*0.5,p(n)表示位置n的概率。

 

 

每一次迭代,都是如此往復,最後的結果就是將區間l/r的所有概率加起來。

 

注意可以使用滾動數組來進行空間優化。

 

0^1=1 1^1=0,如此循環替換。

 

源代碼:

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

double dp[2][220];

int main() {
    int n, m, l, r;

    while (scanf("%d%d%d%d", &n, &m, &l, &r) == 4) {
        if (n == 0 && m == 0 && l == 0 && r == 0)
            break;

        // 初始化位置0的概率爲1
        dp[0][0] = 1;

        //n個格子 
        for (int i = 1; i < n; i++)
            dp[0][i] = 0;

        int now = 0;

        while (m--) {
            // 前進格子數
            int v;
            scanf("%d", &v);

            //對於每一格格子進行計算 
            for (int i = 0; i < n; i++){
                // 注意是環狀,需要取餘計算
                dp[now ^ 1][i] = 0.5 * dp[now][(i - v + n) % n] + 0.5 * dp[now][(i + v) % n];
            }

            now ^= 1;
        }
        double ans = 0;
        for (int i = l - 1; i < r; i++)
            ans += dp[now][i];

        printf("%.4lf\n", ans);
    }
    return 0;
}

個人公衆號(acm-clan):ACM算法日常

專注於基礎算法的研究工作,深入解析ACM算法題,五分鐘閱讀,輕鬆理解每一行源代碼。內容涉及算法、C/C++、機器學習等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章