题解NOIP2016换教室

题目:P1850 换教室 

期望dp。

对于期望dp的套路就是大力分类讨论不同情况然后计算概率。

本题设:f[i][j]:在第i节课 换了j个教室 

·现在要更换教室 :f[i][j][1]
  ·现在更换成功了
    ·上一次要更换教室
      ·上一次更换成功了 : f[i-1][j-1][1]+k[i]*k[i-1]*dis[d[i-1]][d[i]]
      ·上一次更换失败了 : f[i-1][j-1][0]+k[i]*(1-k[i-1])*dis[c[i-1]][d[i]]
    ·上一次不更换教室
      ·上一次更换失败了 : f[i-1][j][0]+k[i]*dis[c[i-1]][d[i]]
  ·现在更换失败了
    ·上一次要更换教室
      ·上一次更换成功了 : f[i-1][j-1][1]+k[i-1]*(1-k[i])*dis[d[i-1]][c[i]]
      ·上一次更换失败了 :f[i-1][j-1][0]+(1-k[i-1])*(1-k[i])*dis[c[i-1]][c[i]]
    ·上一次不更换教室
      ·上一次更换失败了 :f[i-1][j][0]+(1-k[i])*dis[c[i-1]][d[i]]
·现在不更换教室 : f[i][j][0]
  ·现在更换失败了
    ·上一次要更换教室
      ·上一次更换成功了 :f[i-1][j-1][1]+k[i-1]*dis[d[i-1]][c[i]]
      ·上一次更换失败了 :f[i-1][j-1][0]+(1-k[i-1])*dis[c[i-1]][c[i]]
    ·上一次不更换教室
      ·上一次更换失败了 :f[i-1][j][0]+dis[c[i-1]][c[i]]

接下来就是预处理最短路,Floyd很方便。还有就是m次不一定用完,最后在f[n][i][0/1](i∈m)里面求最小值。解决问题!

所以期望dp就是要有耐心地大力分类讨论!

 

 1 #include<stdio.h>
 2 #define it register int
 3 #define il inline
 4 #define Min(a,b) (a<b?a:b) 
 5 const int N=2005;
 6 typedef double db;
 7 int dis[N][N],c[N],d[N],n,m,q,e;
 8 db k[N],f[N][N][2];
 9 il void fr(int &num){
10     num=0;char c=getchar();int p=1;
11     while(c<'0'||c>'9') c=='-'?p=-1,c=getchar():c=getchar();
12     while(c>='0'&&c<='9') num=num*10+c-'0',c=getchar();
13     num*=p;
14 }   
15 int main(){
16     fr(n),fr(m),fr(q),fr(e);
17     for(it i=1;i<=n;++i) fr(c[i]);
18     for(it i=1;i<=n;++i) fr(d[i]);
19     for(it i=1;i<=n;++i) scanf("%lf",&k[i]);
20     for(it i=1;i<=q;++i){
21         for(it j=1;j<=q;++j) dis[i][j]=1e9;
22         dis[i][i]=0;
23     }
24     for(it i=1,u,v,x;i<=e;++i)
25         fr(u),fr(v),fr(x),dis[u][v]=dis[v][u]=Min(dis[u][v],x);
26     for(it k=1;k<=q;++k)
27         for(it i=1;i<=q;++i)
28             for(it j=1;j<=q;++j)
29                 dis[i][j]=Min(dis[i][j],dis[i][k]+dis[k][j]);
30     for(it i=1;i<=n;++i)
31         for(it j=0;j<=m;++j)
32             f[i][j][0]=f[i][j][1]=1e9;
33     f[1][0][0]=0,f[1][1][1]=0;
34     for(it i=2;i<=n;++i)
35         for(it j=0;j<=m;++j){
36              f[i][j][0]=Min(f[i-1][j][1]+k[i-1]*dis[d[i-1]][c[i]]+(1-k[i-1])*dis[c[i-1]][c[i]],f[i-1][j][0]+dis[c[i-1]][c[i]]);
37               if(j) f[i][j][1]=Min(f[i-1][j-1][1]+k[i-1]*k[i]*dis[d[i-1]][d[i]]+k[i-1]*(1-k[i])*dis[d[i-1]][c[i]]+(1-k[i-1])*k[i]*dis[c[i-1]][d[i]]+(1-k[i-1])*(1-k[i])*dis[c[i-1]][c[i]],f[i-1][j-1][0]+k[i]*dis[c[i-1]][d[i]]+(1-k[i])*dis[c[i-1]][c[i]]);
38           }
39     db ans=1e9;
40     for(it i=0;i<=m;++i)
41         ans=Min(ans,Min(f[n][i][0],f[n][i][1]));
42     printf("%.2lf",ans);
43     return 0;
44 }
45 /*
46 f[i][j]:在第i节课 换了j个教室 
47 ·现在要更换教室 :f[i][j][1] 
48     ·现在更换成功了
49         ·上一次要更换教室 
50             ·上一次更换成功了 : f[i-1][j-1][1]+k[i]*k[i-1]*dis[d[i-1]][d[i]] 
51             ·上一次更换失败了 : f[i-1][j-1][0]+k[i]*(1-k[i-1])*dis[c[i-1]][d[i]]
52         ·上一次不更换教室
53             ·上一次更换失败了 : f[i-1][j][0]+k[i]*dis[c[i-1]][d[i]]
54     ·现在更换失败了 
55         ·上一次要更换教室 
56             ·上一次更换成功了 : f[i-1][j-1][1]+k[i-1]*(1-k[i])*dis[d[i-1]][c[i]] 
57             ·上一次更换失败了 :f[i-1][j-1][0]+(1-k[i-1])*(1-k[i])*dis[c[i-1]][c[i]] 
58         ·上一次不更换教室
59             ·上一次更换失败了 :f[i-1][j][0]+(1-k[i])*dis[c[i-1]][d[i]] 
60 ·现在不更换教室 : f[i][j][0]
61     ·现在更换失败了
62         ·上一次要更换教室 
63             ·上一次更换成功了 :f[i-1][j-1][1]+k[i-1]*dis[d[i-1]][c[i]]
64             ·上一次更换失败了 :f[i-1][j-1][0]+(1-k[i-1])*dis[c[i-1]][c[i]]
65         ·上一次不更换教室
66             ·上一次更换失败了 :f[i-1][j][0]+dis[c[i-1]][c[i]] 
67 */ 
View Code

 

 

 

posted @ 2019-11-05 15:48  kylin_xy  阅读(128)  评论(0编辑  收藏  举报