标签:bzoj \n stream div class 就是 1.0 ace nbsp
题目很长,是一道概率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; }
标签:bzoj \n stream div class 就是 1.0 ace nbsp
原文地址:https://www.cnblogs.com/-Chamgin/p/8988197.html