NOIP2016D1T3 换教室 (概率DP)

NOIP2016D1T3 换教室

题目大意:有n个时间段,每个时间段i有两个教室a[i],b[i]可以上课,如果不申请换教室就在教室a[i]上课,如果换教室就在b[i]上课。你最多只能换m次教室。教室之间有一些双向路,保证教室两两可以到达。问上完n节课走路长度的数学期望。

题解:这是一道典型的概率dp题。重要的是状态的设计。

我们令dp[i][j][0/1]代表:第i个时间段换了j次课室这次换(0)还是不换(1)的数学期望。需要注意的是因为要满足dp的无后效性,必须要加上dp状态的第三维代表这一次还还是不换。

根据上次换还是不换和这次换还是不换, 那么就有4种结果。

dp[i][j][0]=min(dp[i-1][j][0]+上次和这次都不换的期望代价,dp[i-1][j][1]+上次换这次不换的期望代价);

dp[i][j][1]=min(dp[i-1][j-1][0]+上次不换这次换的期望代价,dp[i-1][j-1][1]+上次和这次都换的期望代价);

dp边界为dp[1][0][0]=dp[1][0][1]=0;   答案为在i==n中取最小值。

这道题还是有一些细节(期望代价的计算)得看代码的。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2000+10;
const int V=300+10;
const int INF=0x3f3f3f3f;
int n,m,v,e;
int a[N],b[N],map[V][V];
double k[N],dp[N][N][2];

void floyd() {
    for (int k=1;k<=v;k++)
      for (int i=1;i<=v;i++)
        for (int j=1;j<=v;j++) 
          map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&v,&e);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<=n;i++) scanf("%d",&b[i]);
    for (int i=1;i<=n;i++) scanf("%lf",&k[i]);
    memset(map,0x3f,sizeof(map));
    for (int i=1;i<=v;i++) map[i][i]=0;
    for (int i=1;i<=e;i++) {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if (map[x][y]>z) map[x][y]=z;
        if (map[y][x]>z) map[y][x]=z;
    }
    
    floyd();
    
    for (int i=1;i<=n;i++) for (int j=0;j<=m;j++) dp[i][j][0]=dp[i][j][1]=INF; 
    dp[1][0][0]=0;
    dp[1][1][1]=0;
    double ans=INF;
    for (int i=2;i<=n;i++)
        for (int j=0;j<=m;j++) {
            double w1=map[a[i-1]][a[i]],w2=map[a[i-1]][b[i]];
            double w3=map[b[i-1]][a[i]],w4=map[b[i-1]][b[i]];
            dp[i][j][0]=min(dp[i-1][j][0]+w1,dp[i-1][j][1]+w1*(1-k[i-1])+w3*k[i-1]);
            double temp=w1*(1-k[i-1])*(1-k[i])+w2*(1-k[i-1])*(k[i])+w3*(k[i-1])*(1-k[i])+w4*(k[i-1])*(k[i]);
            if (j) dp[i][j][1]=min(dp[i-1][j-1][0]+w1*(1-k[i])+w2*(k[i]),dp[i-1][j-1][1]+temp);
        
            if (i==n) ans=min(ans,min(dp[i][j][0],dp[i][j][1]));
        }
    printf("%.2lf",ans);        
    return 0;
}
原文地址:https://www.cnblogs.com/clno1/p/9644688.html