zoukankan      html  css  js  c++  java
  • 2016 Noip Day1 T3 换教室 【概率DP+Floyd】

    题目:
    https://vijos.org/p/2005
     
    分析:
    这个题就是在不断地蒙你,先给普通的DP套了一个假的概率的外壳,再把弗洛伊德藏在教室和体力的关系间。看起来复杂吓死人,实际上并没有牵扯什么优化或是高级算法。
    所谓的概率,就是给正常的路径值乘了一个限定值,只不过要注意走什么路这个限定值不同。
    我们用f [ i ] [ j ] [ 1 ] 表示考虑前 i 个时间段,已经申请了j 个教室的交换,并且当前教室申请的最小体力消耗。
    我们用f [ i ] [ j ] [ 0 ] 表示考虑前 i 个时间段,已经申请了j 个教室的交换,并且当前教室不申请的最小体力消耗。
    首先肯定要预处理出来所有教室之间的最短路径,再进行DP,此时分情况讨论;(所有变量名与题目一致)
    1、当前教室不打算申请:( A 为原本教室, A'为备份教室,B 同理)
    2016   Noip Day1 T3   换教室 【概率DP+Floyed】 - linda_fcj - Captains Honor
     f [ i ] [ j ] [ 0 ] = min( f [ i ] [ j ] [ 0 ] , f [ i - 1 ] [ j ] [ 0 ] + w [ c [ i-1] ] [ c [ i ] ] ) ;
    表示前一个教室没有申请;
     f [ i ] [ j ] [ 0 ] = min( f [ i ] [ j ] [ 0 ] , f [ i - 1 ] [ j ] [ 1 ] + w [ d [ i - 1 ] ] [ c [ i ] ] * k [ i - 1 ] + w [ c [ i  - 1 ] ] [c [ i ] ] * (1.0-k [ i-1] ));
    绿色表示前一个教室申请了也通过了,蓝色表示没有通过。
    2、当前教室打算申请:
    2016   Noip Day1 T3   换教室 【概率DP+Floyed】 - linda_fcj - Captains Honor
    f [ i ] [ j ] [ 1 ] = min( f [ i ] [ j ] [ 1 ] , f [ i -1 ] [ j-1 ] [ 0 ] + k [ i ] *w[ c [i-1] ] [ d[i] ]+(1.0-k [ i ])*w [ c[i-1] ] [ c[i] ]); //前一个不申请
    f [ i ] [ j ] [ 1 ] = min ( f [ i ] [ j ] [ 1 ] , f [ i -1 ] [ j-1 ] [ 1 ]
                                                     +k [ i-1 ] * k [ i ] * w [ d[i-1] ] [ d[i] ]          //     前一个选上了,后一个也选上了
                                                     +k [ i-1 ] * (1.0-k[i]) * w [ d[i-1] ] [ c[i] ]    //      前一个选上了,后一个没选上
                                                     +(1.0 - k[i-1]) * k [ i ] * w [ c[i-1] ] [ d[i] ]  //      前一个没选上,后一个选上了
                                                     +(1.0 - k [ i-1 ] ) * ( 1.0-k[i] ) * w [ c[i-1] ] [ c[i] ] );//前一个没选上,后一个也没选上
    下面是参考代码:
     
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define inf 1000000007
    using namespace std;
    int n,m,v,e,a,b,ww;
    int c[2020],d[2020],w[330][330];
    double k[2020],f[2020][2020][3],ans=1.0*1e9;
    int main()
    {
     cin>>n>>m>>v>>e;
     for(int i=1;i<=n;i++)
      cin>>c[i];
     for(int i=1;i<=n;i++)
      cin>>d[i];
     for(int i=1;i<=n;i++)
      cin>>k[i];
     for(int i=1;i<=v+10;i++)
      for(int j=0;j<=v+10;j++)
       w[i][j]=1e9;
     for(int i=0;i<=304;i++) w[i][i]=0;
     for(int i=1;i<=e;i++)
     {
      cin>>a>>b>>ww;
      w[a][b]=w[b][a]=min(ww,w[a][b]);
     }
     for(int kk=1;kk<=v;kk++)
      for(int i=1;i<=v;i++)
       for(int j=1;j<=v;j++)
        if(w[i][kk]+w[kk][j]<w[i][j])
         w[i][j]=w[i][kk]+w[kk][j];
     for(int i=1;i<=n;i++)
      for(int j=0;j<=m;j++)
       f[i][j][0]=f[i][j][1]=1.0*1e9;
     f[1][0][0]=f[1][1][1]=0;
     for(int i=2;i<=n;i++)
      for(int j=0;j<=min(i,m);j++)  
      {
       f[i][j][0]=min(f[i][j][0],f[i-1][j][0]+w[c[i-1]][c[i]]);
       f[i][j][0]=min(f[i][j][0],f[i-1][j][1]+w[d[i-1]][c[i]]*k[i-1]+w[c[i-1]][c[i]]*(1.0-k[i-1]));
       if(j>0)
       {
        f[i][j][1]=min(f[i][j][1],f[i-1][j-1][0]+k[i]*w[c[i-1]][d[i]]+(1.0-k[i])*w[c[i-1]][c[i]]);
        f[i][j][1]=min(f[i][j][1],f[i-1][j-1][1]
                                              +k[i-1]*k[i]*w[d[i-1]][d[i]]
                                              +k[i-1]*(1.0-k[i])*w[d[i-1]][c[i]]
                   +(1.0-k[i-1])*k[i]*w[c[i-1]][d[i]]
                   +(1.0-k[i-1])*(1.0-k[i])*w[c[i-1]][c[i]]);
       }
      }
     for(int i=0;i<=m;i++)
      ans=min(min(ans,f[n][i][1]),f[n][i][0]);
     printf("%.2lf",ans);
     return 0;
    } 
    View Code
  • 相关阅读:
    MySql模糊查询like通配符使用详细介绍
    使用powershell批量添加Qt的文件(生成pro)
    宏定义的教训
    使用powershell批量添加Keil和IAR的头文件路径
    python和数据科学(Anaconda)
    CDCE913产生任意频率
    QT中检索设定目录下所有指定文件的方法
    QT中将ASCII转换为对应数值的方法
    STM8如何使用自带的bootloader
    QT中使用函数指针
  • 原文地址:https://www.cnblogs.com/linda-fcj/p/7206329.html
Copyright © 2011-2022 走看看