首先,我们从一节课的教室到另一节课的教室的距离显然需要尽可能小,所以可以预先跑一遍 Floyed ,把距离处理出来
其次,对于这道 DP ,我们设
那么预处理的时候,显然,我们需要将 \(f[1][1][1]\) 以及 \(f[1][0][0]\) 均赋值为 \(0\) ,因为第一节课不管换不换教室,到教室的距离总是为 \(0\)
接下来,我们考虑这些状态之间怎么转移
先看代码:
for(int i=2;i<=n;i++)
{
double len1=dis[t1[i-1]][t1[i]];//上一节和这一节都不换教室
double len2=dis[t1[i-1]][t2[i]];//上一节不换教室,这一节换教室
double len3=dis[t2[i-1]][t1[i]];//上一节换教室,这一节不换教室
double len4=dis[t2[i-1]][t2[i]];//上一节和这一节都换教室
for(int j=0;j<=min(m,i);j++)
{
f[i][j][0]=min(f[i-1][j][0]+len1,f[i-1][j][1]+len3*p[i-1]+len1*(1-p[i-1]));
if(j!=0) f[i][j][1]=min(f[i-1][j-1][0]+len2*p[i]+len1*(1-p[i]),f[i-1][j-1][1]+len1*(1-p[i-1])*(1-p[i])+len2*(1-p[i-1])*p[i]+len3*p[i-1]*(1-p[i])+len4*p[i-1]*p[i]);
}
}
( \(len_i\) 表示教室与教室之间的距离 )
对于第一个 \(f[i][j][0]\) 的转移方程中,由期望公式可以得到 \(len3*p[i-1]+len1*(1-p[i-1])\) ,其中 \(1-p[i-1]\) 为不会发生的概率
对于第二个 \(f[i][j][1]\) 的转移方程中,min 函数左侧的式子可以参考上面 \(f[i][j][0]\) 的式子,min 函数右侧的式子即为在上一次与这一次都提出换教室申请时所有可能出现的情况的枚举讨论
#include<iostream>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
const ll maxn=2e3+10;
int n,m,v,e;
int t1[maxn],t2[maxn],head[maxn],tot;
double dis[maxn][maxn];
double p[maxn];
double f[maxn][maxn][2];
inline double _min(double a,double b)
{
return a < b ? a : b;
}
int main(void)
{
scanf("%d%d%d%d",&n,&m,&v,&e);
for(int i=1;i<=v;i++)
{
for(int j=1;j<i;j++)
{
dis[i][j]=dis[j][i]=999999999;
}
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
f[i][j][0]=f[i][j][1]=999999999;
}
}
for(int i=1;i<=n;i++) scanf("%d",&t1[i]);
for(int i=1;i<=n;i++) scanf("%d",&t2[i]);
for(int i=1;i<=n;i++) scanf("%lf",&p[i]);
for(int i=1;i<=e;i++)
{
int u,v;
double w;
scanf("%d%d%lf",&u,&v,&w);
dis[u][v]=dis[v][u]=min(dis[u][v],w);
}
for(int k=1;k<=v;k++)
{
for(int i=1;i<=v;i++)
{
for(int j=1;j<i;j++)
{
dis[i][j]=dis[j][i]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
f[1][1][1]=f[1][0][0]=0;
for(int i=2;i<=n;i++)
{
double len1=dis[t1[i-1]][t1[i]];
double len2=dis[t1[i-1]][t2[i]];
double len3=dis[t2[i-1]][t1[i]];
double len4=dis[t2[i-1]][t2[i]];
for(int j=0;j<=min(m,i);j++)
{
f[i][j][0]=min(f[i-1][j][0]+len1,f[i-1][j][1]+len3*p[i-1]+len1*(1-p[i-1]));
if(j!=0) f[i][j][1]=min(f[i-1][j-1][0]+len2*p[i]+len1*(1-p[i]),f[i-1][j-1][1]+len1*(1-p[i-1])*(1-p[i])+len2*(1-p[i-1])*p[i]+len3*p[i-1]*(1-p[i])+len4*p[i-1]*p[i]);
}
}
double ans=999999999;
for(int i=0;i<=m;i++)
{
ans=min(f[n][i][0],min(f[n][i][1],ans));
}
printf("%.2lf\n",ans);
return 0;
}