题目
https://www.luogu.org/problemnew/show/P1850
思路
期望DP
很容易想到设f[i][j]为前i个时间段,换了j次,的期望长度。结果发现转移不了,因为我们不知道它的出发点在哪。
自然,数组就变成了f[i][j][0..1]表示是否申请成功
DP时每句所有情况,记住乘上概率
预处理一个floyd即可
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=3e3+77,T=307,inf=0x3f3f3f3f;
int a[N],b[N],n,m,t,p;
double e[N],d[T][T],ans=(double)inf,f[N][N][2];
int main()
{
scanf("%d%d%d%d",&n,&m,&t,&p);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
for(int i=1; i<=n; i++) scanf("%d",&b[i]);
for(int i=1; i<=n; i++) scanf("%lf",&e[i]);
for(int i=1; i<=t; i++) for(int j=1; j<=t; j++) d[i][j]=(double)inf;
for(int i=1; i<=p; i++)
{
int x,y; double z;
scanf("%d%d%lf",&x,&y,&z);
d[x][y]=min(d[x][y],z); d[y][x]=min(d[y][x],z);
}
for(int i=1; i<=t; i++) d[i][i]=0;
for(int k=1; k<=t; k++) for(int i=1; i<=t; i++) for(int j=1; j<=t; j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
for(int i=0; i<=n; i++) for(int j=0; j<=m; j++)
{
f[i][j][0]=inf; f[i][j][1]=inf;
}
f[1][0][0]=0; f[1][1][1]=0;
/* for(int i=1; i<=n; i++) for(int j=1; j<=m; j++)
{
int x=a[i-1],y=b[i-1],x1=a[i],y1=b[i];
f[i][j][0]=min(f[i-1][j][0]+d[x][x1],
f[i-1][j][1]+d[x][x1]*(1-e[i-1])+d[y][x1]*e[i-1]);
f[i][j][1]=min(f[i-1][j-1][0]+d[x][x1]*(1-e[i])*e[i]+d[x][y1]*e[i],
f[i-1][j-1][1]+d[y][x1]*(1-e[i])*e[i-1]+d[y][y1]*e[i]*e[i-1]);
}*/
for(int i=2; i<=n; i++)
{
int mn=min(i,m);
double w1=d[a[i-1]][a[i]],
w2=d[b[i-1]][a[i]]*e[i-1]+d[a[i-1]][a[i]]*(1-e[i-1]),
w3=d[a[i-1]][b[i]]*e[i]+d[a[i-1]][a[i]]*(1-e[i]),
w4=d[a[i-1]][a[i]]*(1-e[i-1])*(1-e[i])+d[a[i-1]][b[i]]*(1-e[i-1])*e[i]+d[b[i-1]][a[i]]*(1-e[i])*e[i-1]+d[b[i-1]][b[i]]*e[i-1]*e[i];
for(int j=0;j<=mn;j++)
{
f[i][j][0]=min(f[i-1][j][0]+w1,f[i-1][j][1]+w2);
if(j)f[i][j][1]=min(f[i-1][j-1][0]+w3,f[i-1][j-1][1]+w4);
}
}
for(int i=0; i<=m; i++) ans=min(ans,min(f[n][i][0],f[n][i][1]));
printf("%.2lf",ans);
}