【NOIP2016】換教室

之前感受很難不會的題,如今隨便就作了呢 =w=ios

原題:ide

 

 

 

 

最初想法,f[i][j][k]表示第i節課,在第j個教室(j=1或0),用了k次機會spa

能想出這個狀態就說明對指望和決策的理解不夠。。。3d

把所在教室表示出來表面上看是表示出了狀態,可是實際上指望是有不肯定性的,若是把所在的點明確地表示出來就消除了這種不肯定性code

正確作法是用j=1或0表示是否選擇換,即用決策表示狀態blog

由於請求之間是相互獨立的,因此能夠直接用p[i]和p[i-1]來控制前後兩個教室ci

若是不懂控制的意思,能夠看以下詳解get

先考慮簡單的狀況,先後都不選string

那麼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]表示換教室編號it

若是前邊選呢

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
相關文章
相關標籤/搜索