[NOIp2016]换教室
Description
Solution
其实只要理解了什么叫期望就可以轻松的DP出来这道题了。
状态设计为\(f(i,j,k)\)表示前\(i\)个点,换了\(j\)个,路径的期望长度,其中\(k=0\)表示\(i\)不换,\(k=1\)表示\(i\)换。
转移为:
\[f(i, j, 0) = \\
\mbox{min} (f(i-1, j, 0) + dis(c_{i-1}, c_i),\\
f(i-1, j, 1) + (1-k_{i-1})dis(c_{i-1}, c_i) + k_{i-1}dis(d_{i-1}, c_i) )
\]
\[f(i, j, 1) =\\
\mbox{min} (f(i-1, j, 0) + (1-k_i)dis(c_{i-1}, c_i) + k_i dis(c_{i-1}, d_i), \\
f(i-1, j, 1) + (1-k_{i-1})(1-k_i)dis(c_{i-1}, c_i) + k_{i-1}(1-k_i)dis(d_{i-1}, c_i) + k_i(1-k_{i-1})dis(c_{i-1}, d_i) + k_{i-1}k_idis(d_{i-1}, d_i) )
\]
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
const int V = 310;
const int N = 2010;
int dis[V][V];
int n, m, v, e;
int c[N], d[N];
double k[N], f[N][N][2];
int main() {
memset(dis, 0x3f, sizeof dis);
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, x, y, z; i <= e; ++i) {
scanf("%d%d%d", &x, &y, &z);
dis[x][y] = dis[y][x] = std::min(dis[x][y], z);
}
for (int i = 1; i <= v; ++i) dis[i][i] = 0;
for (int K = 1; K <= v; ++K)
for (int i = 1; i <= v; ++i)
for (int j = 1; j <= v; ++j)
if (dis[i][j] > dis[i][K] + dis[K][j])
dis[i][j] = dis[i][K] + dis[K][j];
// printf("%d\n", dis[1][2]);
for (int i = 1; i <= n; ++i) for (int j = 0; j <= m; ++j) f[i][j][0] = f[i][j][1] = 1e8;
f[1][0][0] = f[1][1][1] = 0;
for (int i = 2; i <= n; ++i) {
for (int j = 0; j <= m; ++j) if (j <= i) {
if (j <= i - 1)
f[i][j][0] = std::min(
f[i-1][j][0] + dis[c[i]][c[i-1]],
f[i-1][j][1] + dis[c[i]][c[i-1]] * (1.0 - k[i-1]) + dis[c[i]][d[i-1]] * k[i-1]
);
if (j > 0)
f[i][j][1] = std::min(
f[i-1][j-1][0] + dis[d[i]][c[i-1]] * k[i] + dis[c[i]][c[i-1]] * (1.0-k[i]),
f[i-1][j-1][1] + dis[d[i]][d[i-1]] * k[i] * k[i-1] + dis[d[i]][c[i-1]] * k[i] * (1.0-k[i-1]) + dis[c[i]][d[i-1]] * (1.0 - k[i]) * k[i-1] + dis[c[i]][c[i-1]] * (1.0 - k[i]) * (1.0 - k[i-1])
);
}
}
double ans = f[n][0][0];
for (int i = 1; i <= m; ++i) {
ans = std::min(ans, std::min(f[n][i][0], f[n][i][1]));
}
printf("%.2lf\n", ans);
return 0;
}