BZOJ4720 换教室¶
题解¶
发现是一个比较简单的期望dp题,一开始想用一个状态f[i][j]表示前i个数取j个的期望,然后用一个数组记录是否申请以帮助转移,后来发现实际上如果某一个状态选择申请,那后面的状态也可能由当前状态的不申请情况转移过来,那也可以比较简单的设计新状态,f[i][j][0/1],第三位表示当前状态选/不选的期望。
然后就可以用一种简单的方法转移。
1 2 3 4 | f[i][j][0] = std::min(f[i - 1][j][0] + dis[c[i - 1]][c[i]], f[i - 1][j][1] + dis[d[i - 1]][c[i]] * k[i - 1] + dis[c[i - 1]][c[i]] * (1.0 - k[i - 1])); if (j) f[i][j][1] = std::min(f[i - 1][j - 1][0] + k[i] * dis[c[i - 1]][d[i]] + (1.0 - k[i]) * dis[c[i - 1]][c[i]], f[i - 1][j - 1][1] + dis[d[i - 1]][d[i]] * k[i - 1] * k[i] + dis[d[i - 1]][c[i]] * k[i - 1] * (1.0 - k[i]) + dis[c[i - 1]][d[i]] * (1.0 - k[i - 1]) * k[i] + dis[c[i - 1]][c[i]] * (1.0 - k[i - 1]) * (1.0 - k[i])); |
程序¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #define MAX_V 307 int A, B, N, M; int c[2007], d[2007]; double k[2007], dis[MAX_V][MAX_V], f[2007][2007][2], res = 1e9; inline int read () { int x = 0; char c = getchar(); while (c < '0' || '9' < c) c = getchar(); while ('0' <= c && c <= '9') x = x * 10 + c - '0', c = getchar(); return x; } inline void floyd () { for (int i = 1;i <= N; ++i) dis[i][i] = 0; for (int k = 1;k <= N; ++k) for (int i = 1;i <= N; ++i) for (int j = 1;j <= N; ++j) if (i != j) dis[i][j] = std::min(dis[i][j], dis[i][k] + dis[k][j]); } void dp () { for (int i = 1;i <= A; ++i) for (int j = 0;j <= B; ++j) f[i][j][0] = f[i][j][1] = 1e9; f[1][0][0] = f[1][1][1] = 0; for (int i = 2;i <= A; ++i) { for (int j = 0;j <= std::min(B, i); ++j) { f[i][j][0] = std::min(f[i - 1][j][0] + dis[c[i - 1]][c[i]], f[i - 1][j][1] + dis[d[i - 1]][c[i]] * k[i - 1] + dis[c[i - 1]][c[i]] * (1.0 - k[i - 1])); if (j) f[i][j][1] = std::min(f[i - 1][j - 1][0] + k[i] * dis[c[i - 1]][d[i]] + (1.0 - k[i]) * dis[c[i - 1]][c[i]], f[i - 1][j - 1][1] + dis[d[i - 1]][d[i]] * k[i - 1] * k[i] + dis[d[i - 1]][c[i]] * k[i - 1] * (1.0 - k[i]) + dis[c[i - 1]][d[i]] * (1.0 - k[i - 1]) * k[i] + dis[c[i - 1]][c[i]] * (1.0 - k[i - 1]) * (1.0 - k[i])); } } for (int i = 0;i <= B; ++i) res = std::min(res, std::min(f[A][i][0], f[A][i][1])); printf("%.2lf\n", res); } int main () { A = read(), B = read(), N = read(), M = read(); for (int i = 1;i <= A; ++i) c[i] = read(); for (int i = 1;i <= A; ++i) d[i] = read(); int u, v; double w; for (int i = 1;i <= A; ++i) scanf("%lf", k + i); for (int i = 1;i <= N; ++i) for (int j = 1;j <= N; ++j) dis[i][j] = 1e9; for (int i = 1;i <= M; ++i) { u = read(), v = read(), scanf("%lf", &w); dis[u][v] = std::min(dis[u][v], w); dis[v][u] = dis[u][v]; } floyd(); dp(); return 0; } |