方程不难推…出思路太慢了…
定义 d p [ i ] [ j ] dp[i][j] dp[i][j]为第 i i i个时间段花费了 j j j次机会的最小路程
但是无法转移…因为我们不知道上一次在哪个地点
那么定义 d p [ i ] [ j ] [ 0 / 1 ] 表 示 本 次 是 否 申 请 换 教 室 dp[i][j][0/1]表示本次是否申请换教室 dp[i][j][0/1]表示本次是否申请换教室
但是这样还是没有确切知道在哪个地点啊!!
既然是概率期望,就应该知道
对于 d p [ i ] [ j ] [ 0 ] dp[i][j][0] dp[i][j][0], 100 % 100\% 100%在 c i c_i ci位置
对于 d p [ i ] [ j ] [ 1 ] dp[i][j][1] dp[i][j][1], p i p_i pi概率在 d i d_i di位置, 1 − p i 1-p_i 1−pi概率在 d i d_i di位置
所以转移很明了了,枚举本次和上次的状态,根据概率来转移即可
#include <bits/stdc++.h>
using namespace std;
const int inf=1e9;
const int maxn=2009;
int n,m,v,e,c[maxn],d[maxn];
double p[maxn],dis[maxn][maxn],ans=1e9,dp[maxn][maxn][2];
void floyd()
{
for(int i=1;i<=v;i++)
for(int j=1;j<=v;j++)
if( i==j ) dis[i][j]=0;
else dis[i][j]=inf;
for(int i=1;i<=e;i++)
{
int l,r; double w; cin >> l >> r >> w;
dis[l][r]=dis[r][l]=min( dis[l][r],w );
}
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] );
}
int main()
{
cin >> n >> m >> v >> e;
for(int i=1;i<=n;i++) cin >> c[i];
for(int i=1;i<=n;i++) cin >> d[i];
for(int i=1;i<=n;i++) cin >> p[i];
floyd();
for(int i=0;i<=2000;i++)
for(int j=0;j<=2000;j++)
dp[i][j][0]=dp[i][j][1]=inf;
dp[1][0][0]=0;
dp[1][1][1]=0;
for(int i=2;i<=n;i++)//枚举时间
{
int last=min( i,m );
for(int j=0;j<=last;j++)//枚举
{
double q=inf,w=inf;
q=dp[i-1][j][0]+dis[c[i-1]][c[i]];//当前不换,上一次不换
w=dp[i-1][j][1]+dis[c[i-1]][c[i]]*(1-p[i-1])+dis[d[i-1]][c[i]]*p[i-1];
dp[i][j][0]=min( q,w );
q=w=inf;
if( j )
{
q=dp[i-1][j-1][0] + dis[ c[i-1] ][ c[i] ] * ( 1-p[i] ) + dis[ c[i-1] ][ d[i] ] * p[i];
w=dp[i-1][j-1][1]+dis[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i]);
w+=dis[c[i-1]][d[i]]*(1-p[i-1])*p[i]+dis[d[i-1]][c[i]]*p[i-1]*(1-p[i]);
w+=dis[d[i-1]][d[i]]*p[i-1]*p[i];
}
dp[i][j][1]=min( q,w );
if( i==n )
ans=min( ans,min(dp[i][j][0],dp[i][j][1]) );
}
}
if( n==1 ) ans=0;
printf("%.2lf",ans);
}