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 }