bzoj4720 [Noip2016]换教室

来源:互联网 发布:106短信平台软件 编辑:程序博客网 时间:2024/05/18 01:45

题目

震惊,noip竟然考期望dp233。
期望是可以递推的。。。。
f[i][j][0..1]表示第i节课,已经换了j节,第i节换不换教室的期望。这样,就有四种转移,也比较好写,太长了,就不打出来了,看代码吧。

#include<bits/stdc++.h>#define MIN(x,y,z) min(min(x,y),z)using namespace std;int n,m,v,e;int dis[501][501];int c[3001],d[3001];double f[3001];double dp[3001][3001][2];//前i,换了j,第i换不换 double ans;int x,y,z;int read(){    int x=0;    char c=getchar();    while(c>'9'||c<'0')c=getchar();    while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();    return x;}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",&f[i]);    memset(dis,63,sizeof(dis));    for(int i=1;i<=v;i++)dis[i][i]=0;    for(int i=1;i<=e;i++)    {        scanf("%d%d%d",&x,&y,&z);        dis[x][y]=min(dis[x][y],z);        dis[y][x]=min(dis[y][x],z);    }    for(int k=1;k<=v;k++)        for(int i=1;i<=v;i++)            for(int j=1;j<=v;j++)                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);    for(int i=1;i<=n;i++)        for(int j=0;j<=m;j++)            dp[i][j][0]=dp[i][j][1]=1e10;    dp[1][0][0]=dp[1][1][1]=0;    for(int i=2;i<=n;i++)    {        for(int j=0;j<=m;j++)        {            dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][0]+(double)dis[c[i]][c[i-1]]);            dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][1]+dis[c[i]][c[i-1]]*(1-f[i-1])+dis[c[i]][d[i-1]]*f[i-1]);            if(!j)continue;            dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][0]+dis[c[i]][c[i-1]]*(1-f[i])+dis[d[i]][c[i-1]]*f[i]);            double tmp=dis[c[i]][c[i-1]]*(1-f[i])*(1-f[i-1])+dis[c[i]][d[i-1]]*f[i-1]*(1-f[i]);            tmp+=dis[d[i]][c[i-1]]*f[i]*(1-f[i-1])+dis[d[i]][d[i-1]]*f[i]*f[i-1];            dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][1]+tmp);        }    }    ans=1e10;    for(int i=0;i<=m;i++)        ans=MIN(ans,dp[n][i][0],dp[n][i][1]);    printf("%.2f",ans);    return 0;}