• BZOJ4720-换教室


    题目很长,是一道概率dp题,一般需要逆推,但这题结局不确定所以要顺推。

    用f[i][j][k],i表示第i段时间,j表示用了j次申请,k就表示这轮是否用申请。 

    那么要求min(f[n][0~m][0],f[n][0~m][1])

    状态转移方程有点麻烦,需要细心。

    ①前一个不需要申请,当前的时间也不需要申请。这个最容易推出来f[i][j][0]=min(f[i][j][0],(f[i-1][j][0]+dis[c[i-1]][c[i]]))×1.0)

    ②当前j>=1,那么至少可以申请一次。也就是可以前一个时间没申请,当前申请。或者前一个时间申请,当前没申请。

    ③当前j>=2,那么就可以考虑前一段时间也申请了。因为申请分成功和失败,所以这里有4个不同的状况要考虑。分别是:

    申请成功->申请成功

    申请成功->申请失败

    申请失败->申请成功

    申请失败->申请失败

    代码中的_11s表示前一段时间申请了,这一次也申请了,并申请成功。1表示申请了,0表示没申请。s表示成功,f表示失败。

    代码如下:

    #include <iostream>
    #include <string.h>
    #include <stdio.h>
    using namespace std;
    typedef long long ll;
    
    int n,m,v,e;
    int c[2333],d[2333];
    double k[2333];
    int dis[333][333],a,b,cc;
    double f[2333][2333][2];
    int  main(){
        scanf("%d%d%d%d",&n,&m,&v,&e);
        for(int i=1;i<=n;++i)scanf("%d",&c[i]);
        for(int i=1;i<=n;++i)scanf("%d",&d[i]);
        for(int i=1;i<=n;++i)scanf("%lf",&k[i]);
        memset(dis,0x3f,sizeof dis);
        for(int i=1;i<=v;++i)dis[i][i]=0;
        for(int i=1;i<=e;++i){
            scanf("%d%d%d",&a,&b,&cc);
            dis[a][b]=dis[b][a]=min(dis[a][b],cc);
        }
        for(int kk=1;kk<=v;++kk)
            for(int i=1;i<=v;++i)
                for(int j=1;j<=v;++j)
                    dis[i][j]=dis[j][i]=min(dis[i][j],dis[i][kk]+dis[kk][j]);
        for(int i=0;i<=n;++i)for(int j=0;j<=m;++j)
            f[i][j][0]=f[i][j][1]=0x3f3f3f3f;
        f[1][0][0]=f[1][1][1]=0.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]+dis[c[i-1]][c[i]]);
                if(j>=1){
                    double _10s=(f[i-1][j][1]+1.0*dis[d[i-1]][c[i]])*k[i-1];
                    double _10f=(f[i-1][j][1]+1.0*dis[c[i-1]][c[i]])*(1.0-k[i-1]);
                    f[i][j][0]=min(f[i][j][0],_10s+_10f);
                    double _01s=(f[i-1][j-1][0]+1.0*dis[c[i-1]][d[i]])*k[i];
                    double _01f=(f[i-1][j-1][0]+1.0*dis[c[i-1]][c[i]])*(1.0-k[i]);
                    f[i][j][1]=min(f[i][j][1],_01s+_01f);
                }
                if(j>=2){
                    double _11ss,_11ff,_11sf,_11fs;
                    _11ss=(f[i-1][j-1][1]+dis[d[i-1]][d[i]])*k[i-1]*k[i];
                    _11ff=(f[i-1][j-1][1]+1.0*dis[c[i-1]][c[i]])*(1.0-k[i-1])*(1.0-k[i]);
                    _11fs=(f[i-1][j-1][1]+1.0*dis[c[i-1]][d[i]])*(1.0-k[i-1])*k[i];
                    _11sf=(f[i-1][j-1][1]+1.0*dis[d[i-1]][c[i]])*k[i-1]*(1.0-k[i]);
                    double tmp=_11ss+_11ff+_11sf+_11fs;
                    f[i][j][1]=min(f[i][j][1],tmp);
                }
            }
        }
        double ans=0x3f3f3f3f;
        for(int i=0;i<=m;++i)
            ans=min(ans,min(f[n][i][0],f[n][i][1]));
        printf("%.2lf
    ",ans);
        return 0;
    }
  • 相关阅读:
    ZJU_1145 OR POJ_1100 Dreisam Equations
    数据结构基础之队列
    The New Villa
    Mission Impossible 6
    数据结构基础之栈
    POJ_1185_炮兵阵地 dp+状态压缩
    (转载)Dig命令的用法
    (转载)服务发现系统etcd介绍
    golang 导入包
    1.4方程求根之弦截法
  • 原文地址:https://www.cnblogs.com/-Chamgin/p/8988197.html
Copyright © 2020-2023  润新知