UESTC 1652 都市大飙车

本文介绍了一种使用概率动态规划(DP)解决多段图问题的方法,并通过具体实例展示了如何利用滚动数组来实现算法。针对有障碍物的多车道场景,详细解释了状态转移过程及概率计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值