LOJ2360. 「NOIP2016」换教室【概率DP】【Floyed】【傻逼题】

LINK


思路

先floyed出两点最短路
然后就可以直接\(dp_{i,j,0/1}\)表示前i节课选择换j节,换不换当前这一节的最小贡献

直接可以枚举上一次决策的状态计算概率进行统计就可以了


我变量名写重了僵硬了半天。。。。被安排了


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
  bool w = 1;x = 0;
  char c = getchar();
  while (!isdigit(c) && c != '-') c = getchar();
  if (c == '-') w = 0, c = getchar();
  while (isdigit(c)) {
    x = (x<<1) + (x<<3) + c -'0';
    c = getchar();
  }
  if (!w) x = -x;
}
template <typename T>
void Write(T x) {
  if (x < 0) {
    putchar('-');
    x = -x; 
  }
  if (x > 9) Write(x / 10);
  putchar(x % 10 + '0');
}
//----------------------------------------------
const int N = 2010;
const int M = 310;
double g[M][M], p[N];
double dp[N][N][2];
int c[N], d[N];
int n, m, v, e;
int main() {
  Read(n), Read(m), Read(v), Read(e);
  fu(i, 1, n) Read(c[i]);
  fu(i, 1, n) Read(d[i]);
  fu(i, 1, n) scanf("%lf", &p[i]);
  fu(i, 1, v) 
    fu(j, 1, v) g[i][j] = 1e8;
  fu(i, 1, e) {
    int x, y; double w;
    Read(x), Read(y); scanf("%lf", &w);
    g[x][y] = g[y][x] = min(w, g[x][y]);
  }
  fu(i, 1, v) g[i][i] = 0.0;
  fu(k, 1, v)
    fu(i, 1, v) if (i != k)
      fu(j, 1, v) if (j != k)
        g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
  double ans = 1e8;
  fu(i, 1, n)
    fu(j, 0, m) dp[i][j][0] = dp[i][j][1] = 1e8;
  dp[1][0][0] = dp[1][1][1] = 0;
  fu(i, 2, n) {
    fu(j, 0, m) {
      dp[i][j][0] = min(dp[i - 1][j][1] + p[i - 1] * g[d[i - 1]][c[i]] + (1.0 - p[i - 1]) * g[c[i - 1]][c[i]], dp[i - 1][j][0] + g[c[i - 1]][c[i]]);
      if (j) dp[i][j][1] = min(dp[i - 1][j - 1][1] + p[i - 1] * p[i] * g[d[i - 1]][d[i]] + (1.0 - p[i - 1]) * p[i] * g[c[i - 1]][d[i]] + p[i - 1] * (1.0 - p[i]) * g[d[i - 1]][c[i]] + (1.0 - p[i - 1]) * (1.0 - p[i]) * g[c[i - 1]][c[i]], dp[i - 1][j - 1][0] + (p[i] * g[c[i - 1]][d[i]] + (1.0 - p[i]) * g[c[i - 1]][c[i]])); 
    }
  } 
  fu(i, 0, m) ans = min(ans, min(dp[n][i][0], dp[n][i][1]));
  printf("%.2lf", ans);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/dream-maker-yk/p/9784656.html
今日推荐