换教室

方程不难推…出思路太慢了…


定义 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 1pi概率在 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);
}