zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    关于MD5的个人笔记
    QueryString 页面传值方法
    酒店管理系统房态图的效果制作
    开始我的学习之路
    SQL取数据库名,取表名,取列名
    鼠标/键盘事件
    C#皮肤使用例子.
    C#调用WIN API
    C#中定时器的使用方法
    C#随机点名程序例子(名字由配置文件提供)
  • 原文地址:https://www.cnblogs.com/clno1/p/9644688.html
Copyright © 2011-2022 走看看