洛谷P1850 换教室noip提高day1题

本文介绍了一种利用概率动态规划解决教室更换申请问题的方法。具体地,通过定义不同的状态来计算期望体力消耗,最终找到最小化期望消耗的方案。

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

概率期望dp

期望:(百度百科)

概率论和统计学中,数学期望(mean)(或 均值,亦简称期望)是试验中每次可能结果的 概率乘以其结果的总和。是最基本的数学特征之一。它反映随机变量平均取值的大小。
需要注意的是,期望值并不一定等同于常识中的“期望”——“期望值”也许与每一个结果都不相等。(换句话说,期望值是该变量输出值的 平均数。期望值并不一定包含于变量的输出值集合里。)
例如:某城市有10万个家庭,没有孩子的家庭有1000个,有一个孩子的家庭有9万个,有两个孩子的家庭有6000个,有3个孩子的家庭有3000个。 则此城市中任一个家庭中孩子的数目是一个随机变量,记为X。它可取值0,1,2,3。 其中取0的概率为0.01取1的概率为0.9,取2的概率为0.06,取3的概率为0.03。 它的数学期望0×0.01+1×0.9+2×0.06+3×0.03等于1.11,即此城市一个家庭平均有小孩1.11个。
用数学式子表示为E(X)=1.11。
题意中已经给出所有的申请是相互独立事件。本题是一个概率dp:学习资源,洛谷题解。
a[],b[],c[]分别代表原教室,换后的教室,和概率
用f[i][j][0]代表前i个时间段提出了j个申请,而当前第i个没有提出申请,
          f[i][j][1]代表前i个 时间段提出了j个申请,而当前第i个也提出申请,
f[i][j][0],可能的状态来源:(1)f[i-1][j][0],那么当前需要增加体力:p(ai,ai-1)
(2)f[i-1][j][1] 那么i-1有两种状态:通过在bi-1,概率c[i-1]*p(ai,bi-1)
 未通过,在ai-1,概率(1-c[i-1])*p(ai,ai-1)
f[i][j][1],可能的状态来源:(1)f[i-1][j-1][0],那么i有两种状态:通过在bi,概率c[i]*p(bi,ai-1)
 未通过,在ai,概率(1-c[i])*p(ai,ai-1)

(2)f[i-1][j-1][1] 那么i-1有4种状态:都通过在bi,bi-1,概率c[i]*c[i-1];
  i通过,i-1未通过,bi,ai-1
  i未通过,i-1通过   ai,bi-1;
 都未通过,ai,ai-1.
注意初始化,f[i][0[0]直接前缀和。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2010, V = 310;
int a[N], b[N];
double d[V][V];
double c[N];
double f[N][N][2];
int cnt = 0;
int n, m, v, e;
void init()
{
    for (int i=0; i<V; i++)
        for (int j=0; j<V; j++)
            if (i == j) d[i][j] = 0;
            else d[i][j] = 1e9;
    for (int i=0; i<N; i++)
        for (int j=0; j<N; j++)
            f[i][j][0] = f[i][j][1] = 1e9;
    f[1][0][0] = 0; f[1][1][1] = 0;
}
void floyd()
{
    for (int k=1; k<=v; k++)
        for (int i=1; i<=v; i++)
            for (int j=1; j<=v; j++)
                if (d[i][k] + d[k][j] < d[i][j])
                    d[i][j] = d[i][k] + d[k][j];
}
int main()
{
    scanf("%d%d%d%d", &n, &m, &v, &e);
    for (int i=1; i<=n; i++) scanf("%d", &a[i]);
    for (int i=1; i<=n; i++) scanf("%d", &b[i]);
    for (int i=1; i<=n; i++) scanf("%lf", &c[i]);
    init();
    for (int i=1; i<=e; i++)
    {
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        if (x == y) continue;
        if (z < d[x][y]) d[x][y] = z;
        d[y][x] = d[x][y]; //注意题目里说的会有重边的问题。
    }
    floyd();
    for (int i=2; i<=n; i++)
    {
        f[i][0][0] = f[i-1][0][0] + d[a[i-1]][a[i]];
        for (int j=1; j<=min(m, i); j++)
        {//  第i个未申请            第i1个未申请        ,        第i-1个申请,可能通未过                           可能通 过 
            f[i][j][0] = min(f[i-1][j][0] + d[a[i-1]][a[i]], f[i-1][j][1] + d[a[i-1]][a[i]] * (1.0-c[i-1]) + d[b[i-1]][a[i]] * c[i-1]);
        //  第i个申请了   第i-1个未申请    当前申请未通过                   通过 
		    f[i][j][1] = f[i-1][j-1][0] + d[a[i-1]][a[i]] * (1.0-c[i]) + d[a[i-1]][b[i]] * c[i];
		       //第i-1个申请了    两个申请都未通过 
     double t = f[i-1][j-1][1] + d[a[i-1]][a[i]] * (1.0-c[i-1]) * (1.0-c[i]);
     			// 第i-1个通过,i个未通过 
            t += d[b[i-1]][a[i]] * c[i-1] * (1.0-c[i]);
               	// 第i-1个未通过,i个通过  
            t += d[a[i-1]][b[i]] * (1.0-c[i-1]) * c[i];
            	//两个申请都通过啦 
            t += d[b[i-1]][b[i]] * c[i-1] * c[i];
            f[i][j][1] = min(f[i][j][1], t); //式子太长分开写。
        }
    }
    double ans = f[n][0][0];
    for (int i=1; i<=m; i++)
    {
        ans = min(ans, min(f[n][i][0], f[n][i][1]));
    }
    printf("%.2lf", ans);
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值