NOIP2016提高组 Day1 T3 换教室

Posted $mathit{AlphaINF}$

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP2016提高组 Day1 T3 换教室相关的知识,希望对你有一定的参考价值。

 

题目链接:https://www.luogu.org/problemnew/show/P1850

此题正解为dp。

我们先用floyd处理出任意两个教室之间的距离,用dis[i][j]表示。

用f[i][j][0..1]表示在前i个课程中,用了j次换课的机会,第i节课选择换还是不换。

f[i][j][0]可以选择用f[i-1][j][0]更新(即第i-1节课选择不换课),代价为dis[c[i-1]][c[i]]。

同时,第i-1节课也可以选择换课,若换课成功,代价为dis[d[i-1]][c[i]],概率为k[i-1]。若换课不成功,则代价还是dis[c[i-1]][c[i]],概率为(1-k[i-1])。

则f[i][j][0]=min(f[i-1][j][0]+dis[c[i-1]][c[i]],(f[i-1][j-1][1]+dis[d[i-1]][c[i]])*k[i-1]+(f[i-1][j][0]+dis[c[i-1]][c[i]])*(1-k));

 

同理,f[i][j][1]可以选择用f[i-1][j][0]更新,若换课成功,代价为dis[c[i-1]][d[i]],概率为k[i]。若换课不成功,则代价是dis[c[i-1]][c[i]],概率为(1-k[i])。

同时,f[i][j][1]也可以选择用f[i-1][j][1]更新。

若两次换课均成功,代价为dis[d[i-1]][d[i]],概率为k[i]*k[i-1]。

若两次换课均不成功,代价为dis[c[i-1]][c[i]],概率为(1-k[i])*(1-k[i-1])。

若第i次成功而第i-1次不成功,代价为dis[c[i-1]][d[i]],概率为(1-k[i-1])*k[i]。

若第i次不成功而第i-1次成功,代价为dis[d[i-1]][c[i]],概率为k[i-1]*(1-k[i])。

则f[i][j][1]=min((f[i-1][j][0]+dis[c[i-1]][d[i]])*k[i]+(f[i-1][j][0]+dis[c[i-1]][c[i]])*(1-k[i]),f[i-1][j][1] + dis[d[i-1]][d[i]]*k[i]*k[i-1] + dis[c[i-1]][c[i]]*(1-k[i])*(1-k[i-1]) + dis[c[i-1]][d[i]]*(1-k[i-1])*k[i] + dis[d[i-1]][c[i]]*k[i-1]*(1-k[i]))。

 

可以看出每次转移是O(1)的,则时间复杂度为O(n*m)+O(v^3)。

最终结果为min(f[n][i][k]) i∈[0,m],j∈[0,1]。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define M 2002
 5 using namespace std;
 6 int n,m,v,e,c[M]={0},d[M]={0};
 7 double p[M]={0},dis[305][305]={0},f[M][M][2]={0},minn=123456789;
 8 void pmin(double &x,double y){
 9     x=min(x,y);
10 }
11  
12 int main(){
13     scanf("%d%d%d%d",&n,&m,&v,&e);
14     for(int i=1;i<=n;i++) scanf("%d",c+i);
15     for(int i=1;i<=n;i++) scanf("%d",d+i);
16     for(int i=1;i<=n;i++) scanf("%lf",p+i);
17     for(int i=1;i<=v;i++)
18         for(int j=1;j<=v;j++) dis[i][j]=12345678;
19     for(int i=1;i<=e;i++){
20         int x,y,z;scanf("%d%d%d",&x,&y,&z);
21         pmin(dis[x][y],z); pmin(dis[y][x],z);
22     }
23     for(int i=1;i<=v;i++) dis[i][i]=0;
24     for(int k=1;k<=v;k++)
25     for(int i=1;i<=v;i++)
26     for(int j=1;j<=v;j++)
27     dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
28     for(int i=0;i<=n;i++) 
29         for(int j=0;j<=m;j++) f[i][j][0]=f[i][j][1]=12345678;
30     f[1][0][0]=0; f[1][1][1]=0; 
31     for(int i=1;i<n;i++)
32     for(int j=0;j<=min(i,m);j++){
33         pmin(f[i+1][j][0],f[i][j][0]+dis[c[i]][c[i+1]]);
34         double px;px=dis[c[i]][d[i+1]]*p[i+1]+dis[c[i]][c[i+1]]*(1-p[i+1]);
35         pmin(f[i+1][j+1][1],f[i][j][0]+px);
36         px=dis[d[i]][c[i+1]]*p[i]+dis[c[i]][c[i+1]]*(1-p[i]);
37         pmin(f[i+1][j][0],f[i][j][1]+px);
38         px=dis[d[i]][d[i+1]]*p[i]*p[i+1]+dis[d[i]][c[i+1]]*p[i]*(1-p[i+1])+dis[c[i]][d[i+1]]*(1-p[i])*p[i+1]+dis[c[i]][c[i+1]]*(1-p[i])*(1-p[i+1]);
39         pmin(f[i+1][j+1][1],f[i][j][1]+px);
40     }
41      
42     for(int i=0;i<=m;i++){
43         minn=min(minn,f[n][i][0]);
44         minn=min(minn,f[n][i][1]);
45     } 
46     printf("%.2lf\n",minn);
47 }

 

以上是关于NOIP2016提高组 Day1 T3 换教室的主要内容,如果未能解决你的问题,请参考以下文章

NOIP2016 DAY1 T3 换教室

洛谷 P1850 换教室(NOIp2016提高组D1T3)

$NOIP 2016 Day1$ 模拟考试 题解报告

[NOIp2016提高组]换教室

[NOIP2016提高组]换教室

P1850 [NOIP2016 提高组] 换教室