【链接】
bzoj4720
【题目大意】
给你n个时间段,让你挑选每个时间段,选择要上的课程,对于每一个时间段,有一个上被安排上课程的教室和另一个同样上这个课程的教室,但需要申请,申请有通过的概率,你共有m次申请机会。再给你e条路径组成的无向图,通过每条都会耗费一定体力值。如果当前所处的教室到下一个教室是两个不同的教室,就需要从当前这个教室走到另一个教室并花费一点体力值。求上完所有课程因在教室间移动耗费的体力值的总和的期望值最小。
【解题报告】
此题是一道明显的期望DP。
定义:
f[i][j][0]表示当前在i时刻,用了j次机会,此次没有用申请机会的耗费的体力值的总和的最小期望值。
f[i][j][1]表示当前在i时刻,用了j次机会,此次用一次申请机会的耗费的体力值的总和的最小期望值。
推倒:
f[i][j][0]=min(f[i-1][j][0]+cst[a[i-1]][a[i]],f[i-1][j][1]+c[i-1]*cst[b[i-1]][a[i]]+(1-c[i-1])*cst[a[i-1]][a[i]];
if (j) f[i][j][1]=min(f[i-1][j-1][0]+c[i]*cst[a[i-1]][b[i]]+(1-c[i])*cst[a[i-1]][a[i]],f[i-1][j-1][1]+c[i]*(c[i-1]*cst[b[i-1]][b[i]]+(1-c[i-1])*cst[a[i-1]][b[i]])+(1-c[i])*(c[i-1]*cst[b[i-1]][a[i]]+(1-c[i-1])*cst[a[i-1]][a[i]]));
//c[i]是此次申请的成功概率,对于此次申请有c[i]的概率成功和1-c[i]的概率失败。a[i]数组表示被安排上课程的教室,b[i]表示另一个同样上这个课程的教室。
结果:
ans=min(ans,min(f[n][0~m][0],f[n][0~m][1]));
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2005,maxe=305;
int n,m,v,e,a[maxn],b[maxn],cst[maxe][maxe];
double c[maxn],ans,f[maxn][maxn][2];
inline int Read()
{
int res=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') res=res*10+ch-48,ch=getchar();
return res;
}
int main()
{
freopen("4720.in","r",stdin);
freopen("4720.out","w",stdout);
n=Read(); m=Read(); v=Read(); e=Read();
for (int i=1; i<=n; i++) a[i]=Read();
for (int i=1; i<=n; i++) b[i]=Read();
for (int i=1; i<=n; i++) scanf("%lf",&c[i]);
memset(cst,63,sizeof(cst));
for (int i=1; i<=v; i++) cst[i][i]=0;
for (int i=1; i<=e; i++)
{
int x=Read(),y=Read(),z=Read();
if (z<cst[x][y]) cst[x][y]=cst[y][x]=z;
}
for (int k=1; k<=v; k++)
for (int i=1; i<=v; i++)
for (int j=1; j<=v; j++)
if (cst[i][k]+cst[k][j]<cst[i][j]) cst[i][j]=cst[i][k]+cst[k][j];
memset(f,127,sizeof(f));
f[1][0][0]=f[1][1][1]=0;
for (int i=2; i<=n; i++)
for (int j=0; j<=min(i,m); j++)
{
f[i][j][0]=min(f[i-1][j][0]+cst[a[i-1]][a[i]],f[i-1][j][1]+c[i-1]*cst[b[i-1]][a[i]]+(1-c[i-1])*cst[a[i-1]][a[i]]);
if (j) f[i][j][1]=min(f[i-1][j-1][0]+c[i]*cst[a[i-1]][b[i]]+(1-c[i])*cst[a[i-1]][a[i]],f[i-1][j-1][1]+c[i]*(c[i-1]*cst[b[i-1]][b[i]]+(1-c[i-1])*cst[a[i-1]][b[i]])+(1-c[i])*(c[i-1]*cst[b[i-1]][a[i]]+(1-c[i-1])*cst[a[i-1]][a[i]]));
}
ans=1e100;
for (int j=0; j<=m; j++) ans=min(ans,min(f[n][j][0],f[n][j][1]));
printf("%.2lf",ans);
return 0;
}