本篇是一个概率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
#include
#include
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++、机器学习等。