HDU 4576 概率dp

题意

一个圆盘,有N个区域,从1号出发,每次逆时针或顺时针向前走w步,问经过m次后,最终停留在区间【l,r】的概率。

有多个测试用例。
每个测试用例包含几行。
第一行包含四个整数:上述n(1≤n≤200)、m(0≤m≤1,000,000)、l,r(1≤l≤r≤n)。
然后是m行,每行代表一个命令。
命令是整数w(1≤w≤100),表示机器人将为该命令行走的单元长度。
输入端为n=0,m=0,l=0,r=0。
您不应该处理此测试用例。
输出量。
对于输入中的每个测试用例,您应该输出一行具有预期可能性的行。输出应四舍五入到小数点后的4位数字。

分析

dp【i】【j】表示第几次到大i点点概率

每次逆时针或顺时针向前走w步
所以dp【i】【j】=dp【(i+w)%n】【j-1】*0.5 +dp【(i-w+n)%n】【j-1】0.5
或者另一种思路是
dp[ (j+x-1)%n+1 ][!k] += 0.5 * dp[j][k];
dp[ (j+n
100-x-1)%n+1 ][!k] += 0.5 * dp[j][k];
答案就是 把区间里的概率全部加起来

代码

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int main()
{
	int n, m, l, r, x;
	double dp[205][2];
	while(scanf("%d%d%d%d", &n, &m, &l, &r) == 4 && n+m+l+r)
	{
		memset(dp, 0, sizeof(dp));
		dp[1][0] = 1.0;
		int k = 1;
		for(int i=0; i<m; i++)
		{
			scanf("%d", &x);
			k = k ^ 1;
			for(int j=1; j<=n; j++) dp[j][!k] = 0;
			for(int j=1; j<=n; j++)
			{
				if(!dp[j][k]) continue;
				dp[ (j+x-1)%n+1 ][!k] += 0.5 * dp[j][k];
				dp[ (j+n*100-x-1)%n+1 ][!k] += 0.5 * dp[j][k];
			}
		}
		double ans = 0.0;
		for(int i=l; i<=r; i++) ans += dp[i][!k];
		printf("%.4f\n", ans);
	}
	return 0;
}


代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
double dp[210][2];
int main()
{
    double ans;
    int n,m,l,r,w;
    while(scanf("%d%d%d%d",&n,&m,&l,&r)==4 && n+m+l+r)
    {
         dp[0][0] = 1;
         for(int i = 1;i < n;i++)dp[i][0] = 0;
         int t = 0;
         while(m--)
         {
             int v;
             scanf("%d",&v);
             t^= 1;
             for(int i = 0;i < n;i++)
                dp[i][t] = 0.5*dp[(i-v+n)%n][t^1] + 0.5*dp[(i+v)%n][t^1];

         }
         double ans = 0.0;
         for(int i = l-1;i < r;i++)
             ans += dp[i][t];
         printf("%.4lf\n",ans);
           }
    return 0;
}
发布了46 篇原创文章 · 获赞 0 · 访问量 1135

猜你喜欢

转载自blog.csdn.net/weixin_45719073/article/details/104505876
今日推荐