[noip2016]换教室 题解

其实noip考期望就很是可以了,不过,只要大概知道一点期望的知识就可以做出来了。

考虑dp。
每两个教室之间的最短路可以用Floyd预处理,以后O(1)用就好了。
状态f[i][j][0…1]表示前i间教室,换了j间,第i间换不换的期望。

每个状态可以这样更新而来:
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]);
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);
看着挺长的,但实际很简单,差不多就是讨论四种情况,注意一下手不要抖就行了。

#include
#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;
} 

你可能感兴趣的:(刷题总结,动归与递推,概率与期望)