原題傳送門
期望dp
狀態:表示到第個時間點,共計請求次,當前這一個時間點是否請求的答案
預處理:直接預處理最短路
轉移:
Code:
#include <bits/stdc++.h>
#define maxn 2010
using namespace std;
double dp[maxn][maxn][2], k[maxn];
int n, m, v, e, c[maxn], d[maxn], w[maxn][maxn];
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
int main(){
n = read(), m = read(), v = read(), e = read();
for (int i = 1; i <= n; ++i) c[i] = read();
for (int i = 1; i <= n; ++i) d[i] = read();
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)
if (i != j) w[i][j] = 1e9;
for (int i = 1; i <= e; ++i){
int x = read(), y = read(), z = read();
w[x][y] = min(w[x][y], z), w[y][x] = w[x][y];
}
for (int k = 1; k <= v; ++k)
for (int i = 1; i <= v; ++i)
if (i != k)
for (int j = 1; j <= v; ++j)
if (j != k && i != j)
w[i][j] = min(w[i][j], w[i][k] + w[k][j]);
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= m; ++j) dp[i][j][0] = dp[i][j][1] = 1e9;
dp[1][0][0] = dp[1][1][1] = 0;
for (int i = 2; i <= n; ++i){
dp[i][0][0] = dp[i - 1][0][0] + w[c[i - 1]][c[i]];
for (int j = 1; j <= min(m, i); ++j){
int A = c[i - 1], B = d[i - 1], C = c[i], D = d[i];
dp[i][j][0] = min(dp[i - 1][j][0] + w[A][C], dp[i - 1][j][1] + w[A][C] * (1 - k[i - 1]) + w[B][C] * k[i - 1]),
dp[i][j][1] = min(dp[i - 1][j - 1][0] + w[A][C] * (1 - k[i]) + w[A][D] * k[i],
dp[i - 1][j - 1][1] + w[A][C] * (1 - k[i - 1]) * (1 - k[i]) + w[B][C] * k[i - 1] * (1 - k[i]) + w[A][D] * (1 - k[i - 1]) * k[i] + w[B][D] * k[i - 1] * k[i]);
}
}
double ans = 1e9;
for (int i = 0; i <= m; ++i) ans = min(ans, min(dp[n][i][0], dp[n][i][1]));
printf("%.2lf\n", ans);
return 0;
}