本篇是一個概率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++、機器學習等。