首页 > 代码库 > bzoj4720 换教室 概率dp

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(){;}

 

bzoj4720 换教室 概率dp