[ACM] HDU 4576 Robot (概率DP,滚动数组)

来源:互联网 发布:单片机标准中文字库 编辑:程序博客网 时间:2024/06/08 06:34

Robot



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.



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.
Michael wants to know the possibility of the robot stopping in the cell that cell number >= l and <= r after m commands.
 

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).
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.  
The input end with n=0,m=0,l=0,r=0. You should not process this test case.
 

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 215 2 4 4120 0 0 0
 

Sample Output
0.50000.2500
 

Source
2013ACM-ICPC杭州赛区全国邀请赛


解题思路:

题意为有编号1-N的格子围城一个圈,一开始机器人站在1号格子,有M个命令,每个命令机器人走W格,可以顺时针也可以逆时针,问M个命令后,机器人站在格子[L,R] 的概率是多少.

想法大体为暴力计算出M个命令后,每个格子上机器人在的概率,那么 P[ L ] + P[ L+1] + P[ L+2] +............P[R] 即为所求

用dp[i][j] ,表示第i个命令后机器人站在j位置的概率

因为命令数m,0≤m≤1,000,000,不可能开出这么大的数组,又因为第i个命令后机器人所在位置的概率只与第i-1个命令后的机器人所在位置有关,所以可以用滚动数组,dp [2] [j]来表示。滚动数组要求当前状态只和前一个状态有关系,和更早之前的状态没关系,所以之前保存的数空间可以覆盖,重新利用,这样就可以降低空间复杂度,但时间复杂度不变。

滚动数组详解:http://blog.csdn.net/niushuai666/article/details/6677982

代码:

#include <iostream>#include <stdio.h>#include <iomanip>#include <string.h>using namespace std;double dp[2][210];int main(){    int n,m,l,r,cm;    while(scanf("%d%d%d%d",&n,&m,&l,&r)!=EOF)    {        if(n==0&&m==0&&l==0&&r==0)            break;        int d=0;        for(int i=1;i<n;i++)            dp[d][i]=0;        dp[0][0]=1;        while(m--)        {            scanf("%d",&cm);            for(int i=0;i<n;i++)                dp[d^1][i]=0;//新状态下每个位置的概率都为0            for(int i=0;i<n;i++)            {                if(dp[d][i]==0)//加上这一句就不超时了                    continue;                dp[d^1][(i+cm)%n]+=0.5*dp[d][i];                dp[d^1][(i-cm+n)%n]+=0.5*dp[d][i];            }            d^=1;//^1 就是加1或者减1交替进行        }        double ans=0;        for(int i=l-1;i<r;i++)            ans+=dp[d][i];        cout<<setiosflags(ios::fixed)<<setprecision(4)<<ans<<endl;    }    return 0;}


0 0