zoukankan      html  css  js  c++  java
  • 【NOIP2016提高组】换教室

    https://www.luogu.org/problem/show?pid=1850

    题面很长,实质很水的一道期望DP题。题面自带劝退效果。

    首先用Floyd算出任意两点的最短路径。然后设f(i,j,0)为前i节课申请更换j节,且不申请第i节时的最小期望;设f(i,j,1)前i节课申请更换j节,且申请第i节时的最小期望。
    可得下面这个超长的状转方程:
    f(i,j,0)=min{
      f(i-1,j,0) + dist(c[i-1],c[i]),    // 不申请第i-1节
      f(i-1,j,1) + k[i-1]*dist(d[i-1],c[i]) + (1-k[i-1])*dist(c[i-1],c[i])    // 申请第i-1节
    }
    f(i,j,1)=min{
      f(i-1,j-1,0) + k[i]*dist(c[i-1],d[i]) + (1-k[i])*dist(c[i-1],c[i]),    // 不申请第i-1节
      f(i-1,j-1,1) + k[i-1]*k[i]*dist(d[i-1],d[i]) + (1-k[i-1])*k[i]*dist(c[i-1],d[i]) + k[i-1]*(1-k[i])*dist(d[i-1],c[i]) + (1-k[i-1])*(1-k[i])*dist(c[i-1],c[i])    // 申请第i-1节
    }
    注意f(i,0,0)意味着一节课都不申请,需要特判f(i,0,0)=f(i-1,0,0)+dist(c[i-1],c[i])

    #include <cstdio>
    #include <algorithm>
    #define maxv 310
    #define maxn 2010
    using namespace std;
    const int inf = 1000;
    int v, e; // v表示牛牛学校里教室的数量;e表示牛牛的学校里道路的数量
    int dist[maxv][maxv];
    void add_edge(int from, int to, int weight)
    {
        dist[from][to] = min(dist[from][to], weight); //注意重边和自环
        dist[to][from] = dist[from][to];
    }
    void floyd()
    {
        // d(k,i,j)=min{d(k-1,i,j), d(k-1,i,k)+d(k-1,k,j)}
        for (int k = 1; k <= v; k++)
            for (int i = 1; i <= v; i++)
                for (int j = 1; j <= v; j++)
                    dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
    }
    int n, m;        // n表示这个学期内的时间段的数量;m表示牛牛最多可以申请更换多少节课程的教室
    int c[maxn];    // 第i个时间段牛牛被安排上课的教室
    int d[maxn];    // 第i个时间段另一间上同样课程的教室
    double k[maxn]; // 牛牛申请在第i个时间段更换教室获得通过的概率
    void load()
    {
        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", &k[i]);
    
        for (int i = 1; i <= v; i++) //初始化邻接矩阵
        {
            for (int j = 1; j <= v; j++)
                dist[i][j] = inf;
            dist[i][i] = 0;
        }
    
        int tmp1, tmp2, tmp3;
        for (int i = 1; i <= e; i++)
        {
            scanf("%d%d%d", &tmp1, &tmp2, &tmp3);
            add_edge(tmp1, tmp2, tmp3);
        }
    }
    double dp[maxn][maxn][2];
    int main()
    {
        load();
        floyd();
        for (int i = 1; i <= n; i++)
        {
            dp[i][0][0] = dp[i - 1][0][0] + dist[c[i - 1]][c[i]]; // f(i,0,0)意味着一节课都不申请,需要特判
            dp[i][0][1] = 2000000;
            for (int j = 1; j <= m; j++)
            {
                // 第1~i节课,申请更换j节,且不申请第i节时的最小期望
                dp[i][j][0] = min(
                    dp[i - 1][j][0] + dist[c[i - 1]][c[i]],                                                      // 不申请第i-1节
                    dp[i - 1][j][1] + k[i - 1] * dist[d[i - 1]][c[i]] + (1 - k[i - 1]) * dist[c[i - 1]][c[i]] // 申请第i-1节
                    );
    
                // 第1~i节课,申请更换j节,且申请第i节时的最小期望
                dp[i][j][1] = min(
                    dp[i - 1][j - 1][0] + k[i] * dist[c[i - 1]][d[i]] + (1 - k[i]) * dist[c[i - 1]][c[i]],                                                                                                                            // 不申请第i-1节
                    dp[i - 1][j - 1][1] + k[i - 1] * k[i] * dist[d[i - 1]][d[i]] + (1 - k[i - 1]) * k[i] * dist[c[i - 1]][d[i]] + k[i - 1] * (1 - k[i]) * dist[d[i - 1]][c[i]] + (1 - k[i - 1]) * (1 - k[i]) * dist[c[i - 1]][c[i]] // 申请第i-1节
                    );
            }
        }
        printf("%.2f", min(dp[n][m][0], dp[n][m][1]));
        return 0;
    }
  • 相关阅读:
    机器学习 -- 用户画像
    机器学习 -- 分类
    机器学习 -- 聚类
    机器学习 -- 回归
    数据分析 -- 流程
    Nginx + Tomcat7 + redis session一致性问题
    机器学习 -- 信息论
    机器学习 -- 统计与分布
    ElasticSearch 学习一: 基本命令
    问题17:如何将多个小字符串拼接成一个大的字符串
  • 原文地址:https://www.cnblogs.com/ssttkkl/p/7530716.html
Copyright © 2011-2022 走看看