Noip2016 换教室

 

 芒果君:之前考的时候从来没见过期望概率DP,直接就懵了,最后爆搜8分……其实转移没有看上去那么复杂,关键还是要理解原理。

预处理floyd。这道题的转移方向很清晰,也就是当前的选择只受上一次影响。之后需要建立状态之间的联系(转移)。f[时间段][成功次数][成功与否0/1],转移方程只有三个:①坐以待毙,就是不换教室;②换教室。然后之前的状态也有至少两个,难度不大但容易写错,所以在码程序之前先将逻辑列出来就可以减少出错。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cmath>
 6 #define inf 1<<29
 7 using namespace std;
 8 int n,m,v,e,mp[310][310],c[2010],d[2010];
 9 double k[2010],f[2010][2010][2],ans;
10 void floyd(){for(int l=1;l<=v;++l) for(int i=1;i<=v;++i) for(int j=1;j<=v;++j) mp[i][j]=min(mp[i][j],mp[i][l]+mp[l][j]);}
11 int main(){ 
12     int x,y,w;
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",&k[i]);
17     for(int i=1;i<=v;++i) for(int j=1;j<=v;++j) mp[i][j]=(i==j?0:inf);
18     for(int i=0;i<=n;++i) for(int j=0;j<=n;++j) f[i][j][0]=f[i][j][1]=inf;
19     f[1][0][0]=f[1][1][1]=0;
20     while(e--){
21         scanf("%d%d%d",&x,&y,&w);
22         if(x==y) continue;
23         mp[x][y]=mp[y][x]=min(mp[x][y],w);
24     }
25     floyd();
26     for(int i=2;i<=n;++i){
27         f[i][0][0]=f[i-1][0][0]+mp[c[i-1]][c[i]];
28         for(int j=1;j<=min(i,m);++j){
29             f[i][j][0]=min(f[i-1][j][0]+mp[c[i-1]][c[i]],f[i-1][j][1]+mp[d[i-1]][c[i]]*k[i-1]+mp[c[i-1]][c[i]]*(1.0-k[i-1]));
30             f[i][j][1]=min(f[i-1][j-1][0]+mp[c[i-1]][c[i]]*(1.0-k[i])+mp[c[i-1]][d[i]]*k[i],f[i-1][j-1][1]+mp[c[i-1]][c[i]]*(1.0-k[i-1])*(1.0-k[i])+mp[d[i-1]][c[i]]*k[i-1]*(1.0-k[i])+mp[c[i-1]][d[i]]*(1.0-k[i-1])*k[i]+mp[d[i-1]][d[i]]*k[i-1]*k[i]);
31         }
32     }
33     ans=f[n][0][0];
34     for(int i=1;i<=m;++i) ans=min(ans,min(f[n][i][0],f[n][i][1]));
35     printf("%.2lf",ans);
36     return 0;
37 }

 

posted @ 2017-10-25 17:04  五十岚芒果酱  阅读(222)  评论(2编辑  收藏  举报