HDU 4579 Random Walk (解方程)

该博客讨论了HDU 4579题目中,关于在n个位置上进行随机行走的问题。每次行走可以前进1-m步或后退1-m步,也可以选择不动,求从位置1到达位置n的期望步数。博主提出使用动态规划的方法,定义dp[i]为从位置i开始到达n的期望步数,并给出递推公式。通过暴力消元解决n个方程和n个变量的问题,实现O(n * m)复杂度的解决方案。

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

转载请注明出处,谢谢http://blog.youkuaiyun.com/ACM_cxlove?viewmode=contents    by---cxlove

题意 :n个位置,每次可以向前走1-m步或者向后者1-m步,或者不动,概率都可以计算出来。问从1走到n的期望步数。

http://acm.hdu.edu.cn/showproblem.php?pid=4579

由于m非常小,只有5。所以用dp[i]表示从位置i出发到达n的期望步数。

那么dp[n] = 0

dp[i] = sigma(dp[i + j] * p (i , i + j)) + 1 .   (-m <= j <= m)

n个方程,n个变元,由于每个方程中的未知数不多,所以可以暴力消元。

每次的原则是以每个位置的方程,将高位全部消元,利用高位置的残留方程。

比如说以位置 i的方程,保留dp[i] = a1 * dp[i - 1] + a2 * dp[i - 2] …… am * dp[i - m]。

最后的常数便是结果,注意细节,以及小心RE,问题不大。

O(n * m)的复杂度从大到小暴力消元。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 50005;
double p[N][11];
int n , m , c[11];
int l[N] , r[N];
double a[N][11];
double constant[N];
bool zero (double d) {
    const double eps = 1e-6;
    return fabs(d) < eps;
}
int main () {
    #ifndef ONLINE_JUDGE
        freopen ("input.txt" , "r" , stdin);
    #endif
    while (scanf ("%d %d" , &n, &m) != EOF) {
        if (!n & !m) break;
        for (int i = 1 ; i <= n ; i ++) {
            int tot = 0;
            for (int j = 1 ; j <= m ; j ++) {
                scanf ("%d" , &c[j]);
                tot += c[j];
            }
            double other = 1.0;
            for (int j = -m ; j < 0 ; j ++) {
                p[i][j + m] = 0.3 * c[-j] / (1 + tot);
                if (i + j >= 1) other -= p[i][j + m];
            }
            for (int j = 1 ; j <= m ; j ++) {
                p[i][j + m] = 0.7 * c[j] / (1 + tot);
                if(i + j <= n) other -= p[i][j + m];
            }
            p[i][m] = other;
        }
        memset (a , 0 , sizeof(a));
        for (int i = n - 1 ; i > 0 ; i --) {
            l[i] = max(i - m , 1);
            r[i] = min(n , i + m);
            for (int j = 0 ; j < r[i] - l[i] + 1 ; j ++) {
                a[i][j] = p[i][(l[i] + j) - i + m];
            }
            constant[i] = 1.0;
            for (int j = r[i] ; j > i ; j --) {
                if (j == n) a[i][j - l[i]] = 0;
                else {
                    double q = a[i][j - l[i]];
                    if (zero(q)) continue;
                    for (int k = 0 ; k < j - l[j] ; k ++) {
                        a[i][k + l[j] - l[i]] += a[j][k] * q;
                    }
                    a[i][j - l[i]] = 0;
                    constant[i] += constant[j] * q;
                }
            } 
            double q = 1 - a[i][i - l[i]];
            for (int j = 0 ; j < r[i] - l[i] + 1 ; j ++) {
                a[i][j] = a[i][j] / q;
            }
            a[i][i - l[i]] = 0;
            constant[i] = constant[i] / q;
        }
        printf ("%.2f\n" , constant[1]);
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值