cdcq

梦幻小鱼干

导航

【NOIP2016】换教室

以前感觉很难不会的题,现在随便就做了呢 =w=

原题:

 

 

 

 

最初想法,f[i][j][k]表示第i节课,在第j个教室(j=1或0),用了k次机会

能想出这个状态就说明对期望和决策的理解不够。。。

把所在教室表示出来表面上看是表示出了状态,但是实际上期望是有不确定性的,如果把所在的点明确地表示出来就消除了这种不确定性

正确做法是用j=1或0表示是否选择换,即用决策表示状态

因为请求之间是相互独立的,所以可以直接用p[i]和p[i-1]来控制先后两个教室

如果不懂控制的意思,可以看如下详解

先考虑简单的情况,前后都不选

那么f[i][0][k]=min(f[i][0][k],f[i-1][0][k]+d[a[i][0]][a[i-1][0]]),其中d[i][j]表示i和j之间距离,a[i][0]表示原教室编号,a[i][1]表示换教室编号

如果前边选呢

f[i][0][k]=min(f[i][0][k],f[i-1][1][k]+d[a[i][0]][a[i-1][1]]*p[i-1]+d[a[i][0]][a[i-1][0]]*(1-p[i-1])),其中d[i][j]表示i和j之间的距离,p[i]表示第i节申请成功的概率

这里就是所谓的用p[i-1]控制前边的教室

为什么f[i-1][1][k]能直接加而不乘概率呢

注意到,这个公式本来应该是p[i-1]*(第i-1节在a[i][1]的期望值+d[a[i-1][1]][a[i][0]])+(1-p[i-1])*(第i-1节在a[i][0]的期望值+d[a[i-1][0]][a[i][0]])

然后我们可以发现p[i-1]*第i-1节在a[i][1]的期望值+(1-p[i-1])*第i-1节在a[i][0]的期望值正是第i-1节选择申请的期望值

所以把这两项合并,就得到上述公式

这里需要注意理清期望的意义

对于其他两种情况同理

f[i][1][k]=min(f[i][1][k],f[i-1][0][k-1]+d[a[i][1]][a[i-1][0]]*p[i]+d[a[i][0]][a[i-1][0]]*(1-p[i]));

f[i][1][k]=min(f[i][1][k],f[i-1][1][k-1]
+d[a[i][1]][a[i-1][1]]*p[i]*p[i-1]
+d[a[i][1]][a[i-1][0]]*p[i]*(1-p[i-1])
+d[a[i][0]][a[i-1][1]]*(1-p[i])*p[i-1]
+d[a[i][0]][a[i-1][0]]*(1-p[i])*(1-p[i-1]));

还挺有规律的

 

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 const int oo=1000000007;
 8 int rd(){int z=0,mk=1;  char ch=getchar();
 9     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
10     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
11     return z*mk;
12 }
13 int n,o,m,c,a[2100][2];
14 int e[310][310];
15 double p[2100];
16 double f[2100][2][2100];
17 void flyd(){
18     for(int k=1;k<=m;++k)for(int i=1;i<=m;++i)for(int j=1;j<=m;++j)
19         e[i][j]=min(e[i][j],e[i][k]+e[k][j]);
20 }
21 void prvs(){
22     for(int i=1;i<=m;++i){
23         e[i][i]=0;
24         for(int j=i+1;j<=m;++j)
25             e[i][j]=oo,e[j][i]=oo;
26     }
27     for(int i=1;i<=n;++i)for(int j=0;j<=1;++j)
28         for(int k=0;k<=o;++k)  f[i][j][k]=oo;
29 }
30 int main(){
31     //freopen("ddd.in","r",stdin);
32     cin>>n>>o>>m>>c;  prvs();
33     for(int i=1;i<=n;++i)  a[i][0]=rd();
34     for(int i=1;i<=n;++i)  a[i][1]=rd();
35     for(int i=1;i<=n;++i)  scanf("%lf",&p[i]);
36     int l,r,mk;
37     while(c --> 0){
38         l=rd(),r=rd(),mk=rd();
39         e[l][r]=min(e[l][r],mk);
40         e[r][l]=min(e[r][l],mk);
41     }
42     flyd();
43     f[1][0][0]=0,f[1][1][1]=0;
44     for(int i=2;i<=n;++i)for(int k=0;k<=o;++k){
45         f[i][0][k]=min(f[i][0][k],f[i-1][0][k]
46                 +e[a[i][0]][a[i-1][0]]);
47         f[i][0][k]=min(f[i][0][k],f[i-1][1][k]
48                 +e[a[i][0]][a[i-1][1]]*p[i-1]
49                 +e[a[i][0]][a[i-1][0]]*(1-p[i-1]));
50         if(k){
51             f[i][1][k]=min(f[i][1][k],f[i-1][0][k-1]
52                     +e[a[i][1]][a[i-1][0]]*p[i]
53                     +e[a[i][0]][a[i-1][0]]*(1-p[i]));
54             f[i][1][k]=min(f[i][1][k],f[i-1][1][k-1]
55                     +e[a[i][1]][a[i-1][1]]*p[i]*p[i-1]
56                     +e[a[i][1]][a[i-1][0]]*p[i]*(1-p[i-1])
57                     +e[a[i][0]][a[i-1][1]]*(1-p[i])*p[i-1]
58                     +e[a[i][0]][a[i-1][0]]*(1-p[i])*(1-p[i-1]));
59         }
60     }
61     double ans=oo;
62     for(int i=0;i<=o;++i){
63         ans=min(ans,f[n][0][i]);
64         ans=min(ans,f[n][1][i]);
65     }
66     printf("%.2lf\n",ans);
67     return 0;
68 }
View Code

 

posted on 2019-11-04 21:20  cdcq  阅读(155)  评论(0编辑  收藏  举报