zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    56 }
    57 int sb=haha();
    58 int main(){;}
    只要是活着的东西,就算是神我也杀给你看。
  • 相关阅读:
    Python—requests模块详解
    强烈推荐(原创亲测)!!!Fiddler抓取https设置详解(图文)
    dexlib2的源码框架
    Android检测代理
    APP加固反调试(Anti-debugging)技术点汇总
    IDA逆向常用宏定义
    JNI学习积累之一 ---- 常用函数大全
    CMake之CMakeLists.txt编写入门
    Android Project和app中两个build.gradle配置的区别
    更新说明
  • 原文地址:https://www.cnblogs.com/Loser-of-Life/p/7182617.html
Copyright © 2011-2022 走看看