NOIP第一次考期望,着实吓一跳。。。
读入之后,
由于 ,给我们建立了天然的 的机会,
建完图之后,能够顺利的想到dp
状态 表示前 节课,换了 次教室,第 节课有没有换教室 的期望行走的距离
很明显,
1、初始的时候,
2、转移的时候,考虑
首先
之后对于所有的
1) ,因为 不选,所以上一节课的位置固定在 ,有以下可能方案:
①被迫第i节课在
上,有
的概率
②第 节课在 上,有 的概率
前两种都是申请换课的情况
③不考虑换课 百分之一百在 上课。
于是乎就有
dp[i][j][0]=min(dp[i][j][0],/*原最优解*/
min(dp[i-1][j][0]+dis[c[i-1]][c[i]],/*不考虑换课*/
dp[i-1][j][1]+dis[c[i-1]][c[i]]*(1-k[i-1]) /*没换成功*/
+dis[d[i-1]][c[i]]*k[i-1])) /*换成功了*/;
2) 上一节课必换课,以下几种情况情况:
①不去换第 节课,
#1 课换成功, 的可能
#2 课没换成功 的可能
②第 节课换成功了,有 的可能
#1 课换成功, 的可能
#2 课换失败, 的可能
③第 堂课换失败了,有 得可能
#1 课换成功, 的可能
#2 课换失败, 的可能 (同上)
于是乎
dp[i][j][1]=min(dp[i][j][1], /*原先最优解*/
min(dp[i-1][j-1][0]/*i-1不换*/
+dis[c[i-1]][c[i]]*(1-k[i])/*i课换失败*/
+dis[c[i-1]][d[i]]*k[i],/*i课换成功*/
dp[i-1][j-1][1]/*i-1课换成功*/
+dis[d[i-1]][d[i]]*k[i]*k[i-1]/*i-1,i课成功*/
+dis[d[i-1]][c[i]]*(1-k[i])*k[i-1]/*i失败,i-1成功*/
+dis[c[i-1]][d[i]]*k[i]*(1-k[i-1])/*i成功,i-1失败*/
+dis[c[i-1]][c[i]]*(1-k[i])*(1-k[i-1])/*i-1,i都失败*/)) ;
这样就搞定了
3.答案:
#include <bits/stdc++.h>
using namespace std ;
const double inf = 1e17;
const int N = 2010 ;
double dp[N][N][2] ;//dp[i][j][k]表示前i节课,换了j节课,第i-1有没有换
int c[N],d[N],dis[310][310] ;
double k[N] ;
int n,m,v,e ;
int main(){
scanf("%d%d%d%d",&n,&m,&v,&e) ;//时间段,可更换,教室数,道路数
for (int i=1;i<=n;i++) scanf("%d",&c[i]) ;
for (int i=1;i<=n;i++) scanf("%d",&d[i]) ;
for (int i=1;i<=n;i++) scanf("%lf",&k[i]) ;
memset(dis,0x3f,sizeof(dis)) ;
for (int i=1;i<=e;i++){
int a,b,c ;
scanf("%d%d%d",&a,&b,&c) ;
dis[b][a]=dis[a][b]=min(dis[a][b],c) ;
}
for (int K=1;K<=v;K++) //一波Floyd
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<=v;i++) dis[i][i]=dis[i][0]=dis[0][i]=0 ;
for (int i=0;i<=n;i++)
for (int j=0;j<=m;j++)
dp[i][j][1]=dp[i][j][0]=inf ;
dp[1][0][0]=dp[1][1][1]=0 ;
for (int i=2;i<=n;i++){
dp[i][0][0]=dp[i-1][0][0]+dis[c[i-1]][c[i]] ;
for (int j=1;j<=min(i,m);j++){
dp[i][j][0]=min(dp[i][j][0],min(dp[i-1][j][0]+dis[c[i-1]][c[i]],dp[i-1][j][1]+dis[c[i-1]][c[i]]*(1-k[i-1])+dis[d[i-1]][c[i]]*k[i-1])) ;
dp[i][j][1]=min(dp[i][j][1],min(dp[i-1][j-1][0]+dis[c[i-1]][c[i]]*(1-k[i])+dis[c[i-1]][d[i]]*k[i],dp[i-1][j-1][1]+dis[d[i-1]][d[i]]*k[i]*k[i-1]+dis[d[i-1]][c[i]]*k[i-1]*(1-k[i])+dis[c[i-1]][d[i]]*(1-k[i-1])*k[i]+dis[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i]))) ;
}
}
double ans=inf ;
for (int i=0;i<=m;i++) ans=min(ans,min(dp[n][i][0],dp[n][i][1])) ;
printf("%.2lf",ans) ;
}