换教室
换教室(期望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);
}