简要的证明一下floyd算法的正确性.想必大家都做过旅行商问题(状态压缩).floyd就是暴力枚举了每个点的对整幅图的贡献.
然后就是讲下这个题,这个题是个概率dp,因为要求最小.首先得明确dp所表示的含义.我们令f[i][j][0/1]表示我们学到了第i门课,我们用了j次机会,第j次的时候用了/没用的期望最短距离.转移方程就比较容易了.
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define f first
#define s second
const int N=2e3+5;
const int M=3e2+5;
int a[N],b[N];
int dis[M][M];
double f[N][N][2];
double p[N];
int main()
{
int n,m,e,v;
cin>>n>>m>>v>>e;
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",&p[i]);
memset(dis,0x3f,sizeof dis);
for(int i=1;i<=v;i++) dis[i][i]=0;
while(e--)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
dis[x][y]=min(w, dis[x][y]);
dis[y][x]=min(w, dis[y][x]);
}
for(int k=1;k<=v;k++)
{
for(int i=1;i<=v;i++)
{
for(int j=1;j<=v;j++)
{
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
for(int k=0;k<2;k++)
{
f[i][j][k]=2e9;
}
}
}
f[1][0][0]=0,0;f[1][1][1]=0.0;
for(int i=2;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
f[i][j][0]=min(f[i-1][j][0]+dis[a[i-1]][a[i]],f[i-1][j][1]+dis[a[i-1]][a[i]]*(1-p[i-1])+dis[b[i-1]][a[i]]*(p[i-1]));
if(j)
{
f[i][j][1]=min(f[i-1][j-1][0]+(1-p[i])*dis[a[i-1]][a[i]]+(p[i])*dis[a[i-1]][b[i]],f[i-1][j-1][1]+
dis[a[i-1]][a[i]]*(1-p[i])*(1-p[i-1])+
dis[a[i-1]][b[i]]*(p[i])*(1-p[i-1])+
dis[b[i-1]][a[i]]*(1-p[i])*(p[i-1])+
dis[b[i-1]][b[i]]*(p[i])*(p[i-1])
);
}
}
}
double ans=2e9;
for(int i=0;i<=m;i++) ans=min(ans,min(f[n][i][0],f[n][i][1]));
printf("%.2lf\n",ans);
return 0;
}
京公网安备 11010502036488号