换教室

换教室(期望dp)

有一个人要上n节课,每节课可以申请换到另一个教室上课,更换成功的概率是(k_i)。最多可以申请m节课。教室可以看成为一个图,结点数为v,边数为e。从一个教室移动到另一个教室需要一定体力值。求期望最小体力值。

woc,这是个期望dp啊。(f[i][j][0/1])表示上到第i次课,申请了j次换教室,本次是否申请。于是方程推一推就出来了。注意这个东西,它是一系列实验的集合。每个实验的随机变量E,体力值为(x_1)表示不申请换课。体力值为(x_2)表示申请换课。这个值可以通过前一个实验的值推断出来。乘上概率就是体力值的期望。总期望就是所有实验的期望相加。
感觉noip2017无望了。。

#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long LL;
const LL maxn=2005, maxv=500, maxe=100000, INF=1e9;
LL n, m, v, e, c[maxn], d[maxn], dis[maxv][maxv];
double ans=INF, p[maxn], f[maxn][maxn][2];

int main(){
    scanf("%lld%lld%lld%lld", &n, &m, &v, &e);
    for (LL i=1; i<=n; ++i) scanf("%lld", &c[i]);
    for (LL i=1; i<=n; ++i) scanf("%lld", &d[i]);
    for (LL i=1; i<=n; ++i) scanf("%lf", &p[i]);
    LL x, y, z;
    for (LL i=0; i<=v; ++i) for (LL j=0; j<=v; ++j)
        if (i==j) dis[i][j]=0; else dis[i][j]=INF;
    for (LL i=1; i<=e; ++i){
        scanf("%lld%lld%lld", &x, &y, &z);
        dis[x][y]=min(dis[x][y], z); dis[y][x]=min(dis[y][x], z);
    }
    for (LL k=1; k<=v; ++k)
        for (LL i=1; i<=v; ++i)
            for (LL j=1; j<=v; ++j)
                dis[i][j]=min(dis[i][j], dis[i][k]+dis[k][j]);
    f[1][0][1]=INF;
    for (LL i=2; i<=n; ++i)
        for (LL j=0; j<=m; ++j){
            f[i][j][0]=min(f[i-1][j][0]+dis[c[i-1]][c[i]],
                    f[i-1][j][1]+dis[c[i-1]][c[i]]*(1-p[i-1])
                    +dis[d[i-1]][c[i]]*p[i-1]);
            if (!j) f[i][j][1]=INF; else
            f[i][j][1]=min(f[i-1][j-1][0]+dis[c[i-1]][d[i]]*p[i]+
                    dis[c[i-1]][c[i]]*(1-p[i]),
                    f[i-1][j-1][1]+dis[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i])+
                    dis[c[i-1]][d[i]]*(1-p[i-1])*p[i]+
                    dis[d[i-1]][c[i]]*p[i-1]*(1-p[i])+
                    dis[d[i-1]][d[i]]*p[i-1]*p[i]);
        }
    for (LL i=0; i<=m; ++i)
        ans=min(ans, min(f[n][i][0], f[n][i][1]));
    printf("%.2lf", ans);
}