bzoj4720 换教室 概率dp
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4720
重述题意:有n节课,每节课有两个教室同时授课,可以改变m次教室,每次改变有独立的成功率,每次交换教室需要消耗一定体力,求出最低期望消耗体力。(教室数量<=200)
我们可以观察到,教室数量很少,而每次我们都需要处理出两个教室之间的距离,涉及到多个源点,因此我们选择floyd预处理每两个教室之间距离,这是O(n3)的枚举。
随后,我们对每一个状态进行动态规划。设数组f[i][j][k]为当前执行到了第i个节点,申请了j次,这一节点是否申请过(k=0没申请过,k=1申请过)。
接下来我们来考虑当f[i][j][0/1]已经求出时可以转移到的情况。
1、上一次没申请,这一次也没申请。如果能转移就是f[i+1][j][0]=f[i][j][0]+dis[c[i]][c[i+1]],c[i]表示原本所在教室的编号。
2、上一次申请了,这一次没申请。那么我们就要考虑申请成功率了。设第i个事件申请成功率为k[i],失败率为1-k[i]=g[i],如果能转移就是f[i+1][j][0]=f[i][j][1]+k[i]*dis[d[i]][c[i+1]]+g[i]*dis[c[i]][c[i+1]],其中d[i]表示另一个教室编号。
3、上一次没申请,这一次申请了。同理可得f[i+1][j+1][1]=f[i][j][0]+k[i+1]*dis[c[i]][d[i+1]]+g[i+1]*dis[c[i]][c[i+1]]。
4、上一次申请了,这一次也申请了。这种情况要同时考虑两次申请成功率,于是f[i+1][j+1][1]=f[i][j][1]+k[i]*k[i+1]*dis[d[i]][d[i+1]]+k[i]*g[i+1]*dis[d[i]][c[i+1]]+g[i]*k[i+1]*dis[c[i]][d[i+1]]+g[i]*g[i+1]*dis[c[i]]*dis[c[i+1]]。
于是问题得解。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int maxn=2005,maxv=305; 7 int n,m,v,e,a[maxv][maxv],c[maxn],d[maxn]; 8 double f[maxn][maxn][2],k[maxn],g[maxn]; 9 int haha() 10 { 11 //freopen("classrooma.in","r",stdin); 12 //freopen("classrooma.out","w",stdout); 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]),g[i]=1-k[i]; 17 memset(a,0x3f,sizeof(a)); 18 for(int i=1;i<=e;i++) 19 { 20 int x,y,z;scanf("%d%d%d",&x,&y,&z); 21 a[x][y]=a[y][x]=min(z,a[x][y]); 22 } 23 for(int i=1;i<=v;i++)a[i][i]=0; 24 for(int ka=1;ka<=v;ka++) 25 for(int i=1;i<=v;i++) 26 if(i!=ka) 27 for(int j=1;j<=v;j++) 28 if(i!=j&&j!=ka) 29 a[i][j]=min(a[i][j],a[i][ka]+a[ka][j]); 30 for(int i=1;i<=n;i++) 31 for(int j=0;j<=m;j++) 32 { 33 f[i][j][0]=1e18; 34 f[i][j][1]=1e18; 35 } 36 f[1][0][0]=f[1][1][1]=0; 37 for(int i=1;i<n;i++) 38 for(int j=0;j<=m;j++) 39 { 40 int c1=a[c[i]][c[i+1]],c2=a[d[i]][d[i+1]],c3=a[c[i]][d[i+1]],c4=a[d[i]][c[i+1]]; 41 f[i+1][j][0]=min(f[i+1][j][0],f[i][j][0]+c1); 42 f[i+1][j][0]=min(f[i+1][j][0],f[i][j][1]+c1*g[i]+c4*k[i]); 43 if(j<m) 44 { 45 f[i+1][j+1][1]=min(f[i+1][j+1][1],f[i][j][0]+c1*g[i+1]+c3*k[i+1]); 46 f[i+1][j+1][1]=min(f[i+1][j+1][1],f[i][j][1]+c1*g[i]*g[i+1]+c2*k[i]*k[i+1]+c3*g[i]*k[i+1]+c4*k[i]*g[i+1]); 47 } 48 } 49 double ans=1e16; 50 for(int i=0;i<=m;i++) 51 { 52 ans=min(ans,f[n][i][0]); 53 ans=min(ans,f[n][i][1]); 54 } 55 printf("%0.2lf\n",ans); 56 } 57 int sb=haha(); 58 int main(){;}