洛谷P1850 换教室(NOIp2016 Day1 T3)(BZOJ 4720)

来源:互联网 发布:胸痛中心数据填报平台 编辑:程序博客网 时间:2024/06/05 06:35

期望DP 最短路

洛谷题目传送门

BZOJ题目传送门

思路很简单,先Floyd求出所有教室之间的最短路,然后分情况进行讨论来求解期望值。

但是转移方程很长。。。

先定义DP数组:f[i][j][0/1]表示对于前i节课,申请修改其中的j节的期望值,其中0表示第i节不申请修改,1表示申请。

然后有如下四种情况:

①:第i1节和第i节均不修改。
此时成功的概率为1,期望值为1disai1,ai
转移方程:f[i][j][0]=f[i-1][j][0]+dis[a[i-1]][a[i]];

②:第i1节修改,但第i节不修改。
此时成功的概率为proi1,期望值为proi1disbi1,ai
失败的概率为1proi1,期望值为(1proi1)disai1,ai
转移方程:f[i][j][0]=f[i-1][j][1]+pro[i-1]*dis[b[i-1]][a[i]]+(1-pro[i-1])*dis[a[i-1]][a[i]];
f[i][j][0]的实际取值即为上述两种情况的较小值。

③:第i1节和第i节均修改。
此时i1i均成功的概率为proi1proi,期望值为proi1proidisbi1,bi
i1失败,但i成功的概率为(1proi1)proi,期望值为(1proi1)proidisai1,bi
i1成功,但i失败的概率为proi1(1proi),期望值为proi1(1proi)disbi1,ai
i1i均失败的概率为(1proi1)(1proi),期望值为(1proi1)(1proi)disai1,ai
转移方程(很长):

f[i][j][1]=f[i-1][j-1][1]+pro[i]*(pro[i-1]*dis[b[i-1]][b[i]]+(1-pro[i-1])*dis[a[i-1]][b[i]])+(1-pro[i])*(pro[i-1]*dis[b[i-1]][a[i]]+(1-pro[i-1])*dis[a[i-1]][a[i]];

其实就是把以上的期望值相加,再加上之前的状态期望值。

④:第i1节不修改,但是第i节修改。
此时成功的概率为proi,期望值为proidisai1,bi
失败的概率为1proi,期望值为(1proi)disai1,ai
转移方程:f[i][j][1]=f[i-1][j-1][0]++pro[i]*dis[a[i-1]][b[i]]+(1-pro[i])*dis[a[i-1]][a[i]];

f[i][j][1]的实际取值也为上述两种情况的较小值。

然后就好了。

代码:

#include<cstdio>#include<cstring>#include<algorithm>#define MAXN 300#define MAX 2000using namespace std;int n,m,p,q;int a[MAX+5],b[MAX+5],dis[MAXN+5][MAXN+5];double pro[MAX+5],f[MAX+5][MAX+5][2];int main(){    scanf("%d%d%d%d",&p,&q,&n,&m);    for (int i=1;i<=p;i++)        scanf("%d",&a[i]);    for (int i=1;i<=p;i++)        scanf("%d",&b[i]);    for (int i=1;i<=p;i++)        scanf("%lf",&pro[i]);    memset(dis,0x3f,sizeof(dis));    for (int i=1;i<=n;i++){        dis[i][i]=0; dis[0][i]=0;    }    for (int i=1;i<=m;i++){        int u,v,d;        scanf("%d%d%d",&u,&v,&d);        dis[u][v]=min(dis[u][v],d);        dis[v][u]=min(dis[v][u],d);    }    for (int k=1;k<=n;k++)        for (int i=1;i<=n;i++)            for (int j=1;j<=n;j++)                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);    memset(f,127,sizeof(f));    f[0][0][0]=0;    for (int i=1;i<=p;i++){        f[i][0][0]=f[i-1][0][0]+dis[a[i-1]][a[i]];        for (int j=1;j<=min(i,q);j++){            int aa=dis[a[i-1]][a[i]],ab=dis[a[i-1]][b[i]],bb=dis[b[i-1]][b[i]],ba=dis[b[i-1]][a[i]];            f[i][j][0]=min(f[i-1][j][0]+aa,f[i-1][j][1]+pro[i-1]*ba+(1-pro[i-1])*aa);            f[i][j][1]=min(f[i-1][j-1][0]+pro[i]*ab+(1-pro[i])*aa,f[i-1][j-1][1]+pro[i]*(pro[i-1]*bb+(1-pro[i-1])*ab)+(1-pro[i])*(pro[i-1]*ba+(1-pro[i-1])*aa));        }    }    double ans=0x7fffffff;    for (int i=0;i<=q;i++)        ans=min(ans,min(f[p][i][1],f[p][i][0]));    printf("%.2lf",ans);    return 0;}