NOIp 2016 选课 (DP)

Problem

题目太长不复制粘贴了

Solution

经典的期望DP, 当作训练吧。

\(dp[i][j][0 / 1]\)表示前\(i\)门课使用\(j\)次申请换课机会, 本次选(\(1\))/不选(\(0\))体力消耗的最小期望值。

其他都写在注释里了。

#include <algorithm>
#include <cstdio>
#include <cstring>
int n, m, v, e;
int c[2010], d[2010];
double k[2010];
double adj[310][310];
double dp[2010][2010][2], ans(999999999.999999);
int main(int argc, char const *argv[]) {
  // Input
  scanf("%d %d %d %d", &n, &m, &v, &e);
  for (register int i(1); i <= n; ++i) {
    scanf("%d", &c[i]);
  }
  for (register int i(1); i <= n; ++i) {
    scanf("%d", &d[i]);
  }
  for (register int i(1); i <= n; ++i) {
    scanf("%lf", &k[i]);
  }
  memset(adj, 0x43, sizeof(adj));
  {
    register double c;
    for (register int i(1), a, b; i <= e; ++i) {
      scanf("%d %d %lf", &a, &b, &c);
      adj[a][b] = adj[b][a] = std::min(adj[a][b], c);
    }
  }
  // Run Floyd-Warshall algorithm to get the lengths of shortest paths between
  // each pair of classrooms.
  for (register int k(1); k <= v; ++k) {
    adj[k][k] = adj[k][0] = adj[0][k] = 0;
    for (register int i(1); i <= v; ++i) {
      for (register int j(1); j <= v; ++j) {
        adj[i][j] = adj[j][i] = std::min(adj[i][j], adj[i][k] + adj[k][j]);
      }
    }
  }
  // Run Dynamic programming to get the answer.
  memset(dp, 0x43, sizeof(dp));
  dp[1][0][0] = dp[1][1][1] = 0.000000;
  for (register int i(2); i <= n; ++i) {
    for (register int j(0); j <= m && j <= i; ++j) {
      // Not apply this time
      dp[i][j][0] = std::min(
          // Didn't apply for exchange before the previous class
          dp[i - 1][j][0] + adj[c[i - 1]][c[i]],
          // Applied last time
          dp[i - 1][j][1] +
              // Failed last time
              (1.000000 - k[i - 1]) * adj[c[i - 1]][c[i]] +
              // Succeeded last time
              k[i - 1] * adj[d[i - 1]][c[i]]);
      // Apply this time
      if (j >= 1) {
        dp[i][j][1] = std::min(
            // Didn't apply for exchange before the previous class
            dp[i - 1][j - 1][0] +
                // Failed this time
                (1.000000 - k[i]) * adj[c[i - 1]][c[i]] +
                // Succeeded this time
                k[i] * adj[c[i - 1]][d[i]],
            // Applied last time
            dp[i - 1][j - 1][1] +
                // Failed both last and this time
                (1.000000 - k[i - 1]) * (1.000000 - k[i]) *
                    adj[c[i - 1]][c[i]] +
                // Succeeded last time and failed this time
                k[i - 1] * (1.000000 - k[i]) * adj[d[i - 1]][c[i]] +
                // Failed last time and succeeded this time
                (1.000000 - k[i - 1]) * k[i] * adj[c[i - 1]][d[i]] +
                // Succeeded both last and this time
                k[i - 1] * k[i] * adj[d[i - 1]][d[i]]);
      }
    }
  }
  for (register int i(0); i <= m; ++i) {
    ans = std::min(ans, std::min(dp[n][i][0], dp[n][i][1]));
  // Output
  printf("%.2lf\n", ans);
  return 0;
}
posted @ 2018-11-05 17:03  Acenaphthene  阅读(268)  评论(0编辑  收藏  举报