Loading

P1850 [NOIP2016 提高组] 换教室 期望 dp

P1850 [NOIP2016 提高组] 换教室

链接

一道期望 dp 的题目。

设状态为 \(f_{i,j,0/1}\) ,表示考虑了 \(i\) 次上课,一共申请了 \(j\) 次,期望最小值。一开始设计状态有点错误,后面的那个 \(0/1\) 表示成了有没有成功换课。实际上应该考虑到在期望概率的体重根本就没有确定可言,你必须用一个确定的状态。

那么这个状态的转移不难想到:

\[f_{i,j,0}=\min(f_{i-1,j,0}+dis_{c_{i-1},c_i},f_{i-1,j,1}+dis_{d_{i-1},c_i}\times k_i+dis_{c_{i-1},c_i}\times (1-k_i)) \]

另一个有点长:

\[calc_1=f_{i-1,j-1,0}+dis_{c_{i-1},d_i}\times k_i+dis_{c_{i-1},c_i}\times (1-k_i)\\ calc_2=f_{i-1,j-1,1}+dis_{c_{i-1},c_i}\times (1-k_{i-1})\times (1-k_i)+dis_{c_{i-1},d_i}\times (1-k_{i-1})\times k_i\\+dis_{d_{i-1},c_i}\times k_{i-1}\times (1-k_i)+dis_{d_{i-1},d_i}\times k_i\times k_{i-1}\\ f_{i,j,1}=\min(calc_1,calc_2) \]

在实际实现中,需要注意 dp 的预处理。为了防止无效状态对有效状态的干扰,建议先全部初始化一个很大的值。关于浮点数的 memset 可以参考这篇博客

这个题对初始化的要求比较高。转移不难。

代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 310
#define M 2010
using namespace std;

const ll INF=100000000000000000;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

template<typename T> inline T Min(T a,T b){
    return a<b?a:b;
}

int n,m,v,e,c[M],d[M];
dd k[M],f[2][M][M],dis[N][N],ans=INF;

int main(){
    read(n);read(m);read(v);read(e);
    for(int i=1;i<=n;i++) read(c[i]);
    for(int i=1;i<=n;i++) read(d[i]);
    for(int i=1;i<=n;i++) scanf("%lf",&k[i]);
    memset(dis,0x41,sizeof(dis));
    for(int i=1;i<=v;i++)
        for(int j=1;j<=v;j++) dis[i][j]=INF;
    for(int i=1;i<=e;i++){
        int from,to,w;read(from);read(to);read(w);
        if(from==to) continue;
        dis[from][to]=Min(dis[from][to],(dd)w);
        dis[to][from]=Min(dis[to][from],(dd)w);
    }
    for(int i=1;i<=v;i++) dis[i][i]=0;
    for(int i=1;i<=v;i++)
        for(int j=1;j<=v;j++)
            for(int k=1;k<=v;k++)
                if(dis[j][k]>dis[j][i]+dis[i][k]) dis[j][k]=dis[j][i]+dis[i][k];
    memset(f,0x41,sizeof(f));
    f[0][1][0]=0;f[1][1][1]=0;
    for(int i=2;i<=n;i++) f[0][i][0]=f[0][i-1][0]+dis[c[i-1]][c[i]];
    for(int i=2;i<=n;i++){
        for(int j=1;j<=m&&j<=i;j++){
            f[0][i][j]=Min(f[0][i][j],Min(f[0][i-1][j]+dis[c[i-1]][c[i]],
            f[1][i-1][j]+dis[d[i-1]][c[i]]*k[i-1]+dis[c[i-1]][c[i]]*(1-k[i-1])));//the first zhuangyi
            f[1][i][j]=Min(f[1][i][j],Min(f[0][i-1][j-1]+dis[c[i-1]][d[i]]*k[i]+dis[c[i-1]][c[i]]*(1-k[i]),
            f[1][i-1][j-1]+dis[c[i-1]][c[i]]*(1-k[i])*(1-k[i-1])+dis[c[i-1]][d[i]]*k[i]*(1-k[i-1])
            +dis[d[i-1]][c[i]]*(1-k[i])*k[i-1]+dis[d[i-1]][d[i]]*k[i]*k[i-1]));
        }
    }
    for(int i=0;i<=m;i++) ans=Min(ans,Min(f[0][n][i],f[1][n][i]));
    printf("%0.2lf\n",ans);
    return 0;
}
posted @ 2021-07-09 17:16  hyl天梦  阅读(36)  评论(0编辑  收藏  举报