测试地址:换教室
做法:设f[i][j][0/1]表示前i个教室选j个申请,其中第i个不申请或申请(最后一个0或1)的最小期望,发现满足动态规划的无后效性原则,再根据和的期望等于期望的和,得到状态转移方程(太长就不在这写了,直接看代码吧),于是用Floyd预处理出两点之间的最短路即可。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,v,e;
int c[2010],d[2010];
double f[2][2010][2],g[310][310],p[2010],inf=1000000.0*1000000.0,dis;
void floyd()
{
for(int k=1;k<=v;k++)
for(int i=1;i<=v;i++)
for(int j=1;j<=v;j++)
g[i][j]=g[j][i]=min(g[i][k]+g[k][j],g[i][j]);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&v,&e);
for(int i=1;i<=v;i++)
for(int j=1;j<=v;j++)
{
if (i!=j) g[i][j]=inf;
else g[i][j]=0;
}
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1;i<=n;i++) scanf("%d",&d[i]);
for(int i=1;i<=n;i++) scanf("%lf",&p[i]);
for(int i=1,a,b;i<=e;i++)
{
scanf("%d%d%lf",&a,&b,&dis);
g[a][b]=g[b][a]=min(g[a][b],dis);
}
floyd();
int now=1,past=0;
memset(f,0,sizeof(f));
f[0][0][1]=inf;
for(int i=2;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
f[now][j][0]=f[now][j][1]=inf;
f[now][j][0]=min(f[now][j][0],f[past][j][0]+g[c[i-1]][c[i]]);
f[now][j][0]=min(f[now][j][0],f[past][j][1]
+p[i-1]*g[d[i-1]][c[i]]+(1-p[i-1])*g[c[i-1]][c[i]]);
if (j>0&&p[i])
{
f[now][j][1]=min(f[now][j][1],f[past][j-1][0]
+p[i]*g[c[i-1]][d[i]]+(1-p[i])*g[c[i-1]][c[i]]);
f[now][j][1]=min(f[now][j][1],f[past][j-1][1]
+p[i-1]*p[i]*g[d[i-1]][d[i]]+(1-p[i-1])*p[i]*g[c[i-1]][d[i]]
+p[i-1]*(1-p[i])*g[d[i-1]][c[i]]+(1-p[i-1])*(1-p[i])*g[c[i-1]][c[i]]);
}
}
swap(now,past);
}
printf("%.2lf",min(f[past][m][0],f[past][m][1]));
return 0;
}