P1850 [NOIP2016 提高組] 換教室 題解
阿新 • • 發佈:2022-05-28
題目大意
有 \(n\) 個時間段,有 \(2n\) 個課程,在第 \(i\) 個時間段的時候,有兩個教室 \(c_i\) 和 \(d_i\) ,第 \(i\) 個時間段申請換教室通過的概率為 \(k_i\)。
可以選擇 \(m\) 個時間段進行換教室,也可以換不到 \(m\) 個教室。
所在大學是一個 \(v\) 個點,\(e\) 條邊的圖,由雙向邊連線,通過每條路的消耗體力不一樣,要求最小化申請後在教室之間移動的體力值總和的期望。
\(\text{Data Range:} 1 \leq m \leq n \leq 2000,v \leq 300\)。
首先要求一個任意兩點之間最短路,這個可以直接 \(v^3\)
然後考慮設立 \(dp_{i,j,0/1}\) 表示前 \(i\) 個時間段中,有 \(j\) 個時間段換了教室,我當前換沒換教室的期望消費體力。
轉移,直接轉移:
\[dp_{i,j,0} = \min(dp_{i-1,j,0} + dis_{c_{i-1},c_i}, dp_{i-1,j,1} + k_{i-1}\times dis_{d_{i-1},c_i} + (1 - k_{i - 1}) \times dis_{c_{i-1}, c_i}) \]\(dp_{i,j,1}\)
// 德麗莎你好可愛德麗莎你好可愛德麗莎你好可愛德麗莎你好可愛德麗莎你好可愛 // 德麗莎的可愛在於德麗莎很可愛,德麗莎為什麼很可愛呢,這是因為德麗莎很可愛! #include <bits/stdc++.h> #define int long long using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while( !isdigit(ch) ) { if(ch == '-') f = -1; ch = getchar(); } while( isdigit(ch) ) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } return x * f; } const int N = 2e5, inf = 1e17; int n, m, v, e, c[N], d[N]; double k[N], dp[3005][3005][2], ans = inf, dis[305][305]; void chkmin(double &x,double y) { if (y < x) x = y; } signed 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++) dis[i][j] = inf; for (int i = 1; i <= e; i++) { int a = read(), b = read(), c = read(); dis[a][b] = dis[b][a] = min(dis[a][b], (double)c); } for (int k = 1; k <= v; k++) for (int i = 1; i <= v; i++) for (int j = 1; j <= v; j++) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); for (int i = 1; i <= v; i++) dis[i][0] = dis[0][i] = dis[i][i] = 0; for (int i = 0; i <= n; i++) for (int j = 0; j <= m; j++) dp[i][j][0] = dp[i][j][1] = inf; dp[1][1][1] = dp[1][0][0] = 0; for (int i = 2; i <= n; i++) { dp[i][0][0] = dp[i - 1][0][0] + dis[c[i - 1]][c[i]]; for (int j = 1; j <= min(i, m); j++) { chkmin(dp[i][j][0], dp[i - 1][j][0] + dis[c[i - 1]][c[i]]); chkmin(dp[i][j][0], dp[i - 1][j][1] + (double) (1.0 - k[i - 1]) * dis[c[i - 1]][c[i]] + (double) k[i - 1] * dis[d[i - 1]][c[i]]); chkmin(dp[i][j][1], dp[i - 1][j - 1][0] + (double) (1.0 - k[i]) * dis[c[i - 1]][c[i]] + (double) k[i] * dis[c[i - 1]][d[i]] ); chkmin(dp[i][j][1], dp[i - 1][j - 1][1] + (double) k[i - 1] * k[i] * dis[d[i - 1]][d[i]] + (double) k[i - 1] * (1.0 - k[i]) * dis[d[i - 1]][c[i]] + (double) (1.0 - k[i - 1]) * (1.0 - k[i]) * dis[c[i - 1]][c[i]] + (double) (1.0 - k[i - 1]) * k[i] * dis[c[i - 1]][d[i]] ); } } for (int i = 0; i <= m; i++) { ans = min(ans, dp[n][i][0]); ans = min(ans, dp[n][i][1]); } printf("%.2lf\n", ans); return 0; }