Noip 2016 换教室 - 期望DP

49 篇文章 0 订阅
18 篇文章 0 订阅

期望反映了一个随机变量的平均结果,是所有可能结果的概率乘上结果的和。例如对于一个随机变量x,1/3几率变为1,1/3几率变为2,1/3几率变为3,则x的期望值为

131+132+133=2 1 3 ∗ 1 + 1 3 ∗ 2 + 1 3 ∗ 3 = 2

期望具有线性性质,我们可以根据加法原理和乘法原理来对期望进行计算

可以发现,最终方案是某种决策集合,而决策是没有概率的,所以每个状态应该取一个最优决策的期望消费,而不是各种决策搞一下期望和什么的,期望体力是确定的,能使期望体力不同是决策不同的原因
就是。。。一个状态只能由前面阶段的一个状态转移过来,因为一个人不能同时处于两种状态,最终方案是每个决断取了一个决策构成的集合

f(i,j,0/1) f ( i , j , 0 / 1 ) 表示到了第i节课,申请j次,第i节课是否申请的最小体力期望(申请需要一次提交)
那么转移就要在多重情况中取最优的,分别为:

i不申请,i-1申请成功
i不申请,i-1申请失败
i申请成功,i-1申请成功
i申请成功,i-1申请失败
i申请失败,i-1申请成功
i申请失败,i-1申请失败
不提交任何申请

具体的转移方程看代码吧。。。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl; 
const int MAXN = 2000 + 10;
int n,m,v,e,c[MAXN],d[MAXN];
double g[310][310],k[MAXN],f[MAXN][MAXN][2],ans = 1e30;
void floyed() {
    for(int k=1; k<=v; k++)
        for(int i=1; i<=v; i++)
            for(int j=1; j<=v; j++)
                g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
void solve() {
    for(int i=2; i<=n; i++) 
        for(int j=0; j<=m; j++)
            if(j==0)
                f[i][j][0] = f[i-1][j][0] + g[c[i-1]][c[i]];            
            else {
                f[i][j][0] = min( f[i-1][j][0] + g[c[i-1]][c[i]], f[i-1][j][1] + g[d[i-1]][c[i]] * k[i-1] + g[c[i-1]][c[i]] * (1-k[i-1]) );
                f[i][j][1] = min( f[i-1][j-1][0] + g[c[i-1]][d[i]] * k[i] + g[c[i-1]][c[i]] * (1-k[i]),
                f[i-1][j-1][1] 
                + g[d[i-1]][d[i]] * k[i-1] * k[i]
                + g[d[i-1]][c[i]] * k[i-1] *(1-k[i])
                + g[c[i-1]][d[i]] * (1-k[i-1]) * k[i]
                + g[c[i-1]][c[i]] * (1-k[i-1]) * (1-k[i]) );  
            }
}
int main() {
    cin >> n >> m >> v >> e;
    for(int i=1; i<=n; i++) 
        cin >> c[i];
    for(int i=1; i<=n; i++) 
        cin >> d[i];
    for(int i=1; i<=n; i++) 
        cin >> k[i];
    for(int i=1; i<=v; i++) {
        for(int j=1; j<=v; j++) 
            g[i][j] = 1e30;
        g[i][i] = 0;
    }
    for(int i=0; i<=n; i++)
        for(int j=0; j<=m; j++)
            f[i][j][0] = f[i][j][1] = 1e30;
    for(int i=1; i<=e; i++) {
        int a, b;
        double z;
        cin >> a >> b >> z;
        g[a][b] = g[b][a] = min(g[a][b], z);
    }
    floyed();
    f[1][0][0] = 0;
    f[1][1][1] = 0;
    solve();
    ans = 1e30;
    for(int i=0; i<=m; i++)
        ans = min(ans, min(f[n][i][0], f[n][i][1]));
    printf("%.2lf",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值