【NOIp2016 day1t3】换教室

NOIP第一次考期望,着实吓一跳。。。

读入之后,

由于 n <= 200 ,给我们建立了天然的 f l o y d 的机会,

建完图之后,能够顺利的想到dp

状态 d p [ i ] [ j ] [ k ] 表示前 i 节课,换了 j 次教室,第 i 1 节课有没有换教室 k 的期望行走的距离

期望友情链接

很明显,

1、初始的时候, d p [ 1 ] [ 0 ] [ 0 ] = d p [ 1 ] [ 1 ] [ 1 ] = 0

2、转移的时候,考虑

首先 d p [ i ] [ 0 ] [ 0 ] = d p [ i 1 ] [ 0 ] [ 0 ] + d i s [ c [ i 1 ] > c [ i ] ]

之后对于所有的 j m i n ( i , m ) ,

扫描二维码关注公众号,回复: 2538095 查看本文章

1) d p [ i ] [ j ] [ 0 ] ,因为 i 1 不选,所以上一节课的位置固定在 c [ i 1 ] ,有以下可能方案:

被迫第i节课在 c [ i ] 上,有 ( 1 k [ i ] ) 的概率

②第 i 节课在 d [ i ] 上,有 k [ i ] 的概率

前两种都是申请换课的情况

③不考虑换课 百分之一百在 c [ 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) d p [ i ] [ j ] [ 1 ] 上一节课必换课,以下几种情况情况:

①不去换第 i 1 节课,

#1 i 课换成功, k [ i ] 的可能

#2 i 课没换成功 ( 1 k [ i ] ) 的可能

②第 i 1 节课换成功了,有 k [ i 1 ] 的可能

#1 i 课换成功, k [ i ] 的可能

#2 i 课换失败, 1 k [ i ] 的可能

③第 i 1 堂课换失败了,有 ( 1 k [ i 1 ] 得可能

#1 i 课换成功, k [ i ] 的可能

#2 i 课换失败, 1 k [ i ] 的可能 (同上)

于是乎

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.答案: min i = 0 m m i n ( d p [ n ] [ i ] [ 0 ] , d p [ n ] [ i ] [ 1 ] )

#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) ;
} 

猜你喜欢

转载自blog.csdn.net/HQG_AC/article/details/81335962