题目很长,是一道概率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\n",ans);
    return 0;
}

 

posted on 2018-05-03 23:28  chagin  阅读(168)  评论(0编辑  收藏  举报