题目链接:http://acm.uestc.edu.cn/#/problem/show/1652
解法:多段图问题,用滚动数组,转移很好想。
概率DP
算法复杂度:O(N*M*log N)
用kk[i]记录第i个障碍物的位置
pos=(b-1)*m+a;
kk[i]=pos;
dp1[j]记录当前所有车道安全的概率
dp2[j]记录下一步所有车道安全的概率
初始化:memset(dp1,0,sizeof(dp1));dp1[p]=1;
for(i=1;i<=n;i++)
{
memset(dp2,0,sizeof(dp2));
for(j=1;j<=m;j++)
{
如果该位置有障碍 dp2[j]=0
否则:
如果m=1 dp2[j]=dp1[j]
否则:
如果j=2 dp2[j]+=dp1[j-1]/2 如果j>2 dp2[j]+=dp1[j-1]/3
如果1

#include <bits/stdc++.h>
using namespace std;
const int maxn = 30010;
int m, k, n, p, a, b, kk[maxn];
double dp1[maxn], dp2[maxn];
double dp[2][maxn];
bool pos[1010][30010];
int now=0,pre=1;
int main()
{
    scanf("%d %d %d", &m,&k,&n);
    scanf("%d", &p);
    bool flag = 1;
    for(int i=1; i<=k; i++){
        scanf("%d %d", &a,&b);
        if(b<=n){
// int pos=(b-1)*m+a;
// kk[i]=pos;
            pos[b][a] = 1;
            flag = 0;
        }
    }
    if(m == 1){
        if(!flag){
            puts("0.000000");
        }
        else{
            puts("1.000000");
        }
        return 0;
    }
// memset(dp1,0,sizeof(dp1));
// dp1[p]=1;
// for(int i=1; i<=n; i++){
// memset(dp2,0,sizeof(dp2));
// for(int j=1; j<=m; j++){
// int cur = (i-1)*m+j;
// int pos = upper_bound(kk+1,kk+k+1,cur)-kk;
// pos--;
// if(kk[pos]==cur){
// dp2[j]=0;
// }
// else{
// if(m==1) dp2[j]=dp1[j];
// else{
// if(j==2) dp2[j]+=dp1[j-1]/2;
// if(j>2) dp2[j]+=dp1[j-1]/3;
// if(j>1&&j<m) dp2[j]+=dp1[j]/3;
// if(j==1||j==m) dp2[j]+=dp1[j]/2;
// if(j==m-1) dp2[j]+=dp1[j+1]/2;
// if(j<m-1) dp2[j]+=dp1[j+1]/3;
// }
// }
// }
// for(int j=1; j<=m; j++) dp1[j]=dp2[j];
// }
// double ans=0;
// for(int j=1; j<=m; j++){
// ans+=dp1[j];
// }
// printf("%.6f\n", ans);
    dp[now][p]=1;
    for(int i=1; i<=n; i++){
        swap(now, pre);
        memset(dp[now],0,sizeof(dp[now]));
        for(int k=1; k<=2; k++){
            if(!pos[i-1][1]){
                dp[now][k]+=dp[pre][1]/2.0;
            }
        }
        for(int k=m-1; k<=m; k++){
            if(!pos[i-1][m]){
                dp[now][k]+=dp[pre][m]/2.0;
            }
        }
        for(int j=2; j<m; j++){
            for(int k=j-1; k<=j+1; k++){
                if(!pos[i-1][j]){
                    dp[now][k]+=dp[pre][j]/3.0;
                }
            }
        }
    }
    double ans=0;
    for(int j=1; j<=m; j++){
        if(!pos[n][j]){
            ans+=dp[now][j];
        }
    }
    printf("%.6f\n", ans);
    return 0;
}