1. 程式人生 > >NOIP 2016 換教室 | 概率DP

NOIP 2016 換教室 | 概率DP

方案 noi main strong can style urn getchar pri

設 dp[i][j][0] 和 dp[i][j][1] 表示在前 i 個裏面換了 j 個的最優方案,0 表示當前換,1 表示當前不換。

分為以下幾種情況討論:

當前點不換,上一個不換;

      上一個換(失敗 + 成功)。

當前點換(失敗 + 成功),上一個不換;

             上一個換(失敗 + 成功)。

得出轉移方程如下:

初始條件 dp[1][0][0] = dp[1][1][1] = 0

dp[i-1][j][0] + floyd[c[i-1]][c[i]]

dp[i-1][j][1] + floyd[d[i-1]][c[i]] * k[i-1] + floyd[c[i-1]][c[i]] * (1 - k[i-1])

dp[i-1][j-1][0] + floyd[c[i-1]][d[i]] * k[i] + floyd[c[i-1]][c[i]] * (1 - k[i])

dp[i-1][j-1][1] + floyd[d[i-1]][d[i]] * k[i-1] * k[i] + floyd[d[i-1]][c[i]] * k[i-1] * (1 - k[i]) + floyd[c[i-1]][d[i]] * (1 - k[i-1]) * k[i] + floyd[c[i-1]][c[i]] * (1 - k[i-1]) * (1 - k[i])

最後就是不要忘記 j = 0 的時候是沒有 ③ ④ 種情況的,而且 ans 只在 dp[n][ ][ ] 處取,不要把中間狀態也打擂了。

 1 #include <cstdio>
 2 #include <string>
 3 #include <cstring>
 4 
 5 const int INF = 0x3f3f3f3f;
 6 
 7 int read() {
 8     int x = 0; char c = getchar();
 9     while (!isdigit(c)) c = getchar();
10     while (isdigit(c)) {
11         x = (x << 3) + (x << 1) + (c ^ 48
); 12 c = getchar(); 13 } 14 return x; 15 } 16 17 double fmin(double x, double y) { 18 return y > x ? x : y; 19 } 20 21 int c[2005], d[2005]; 22 double k[2005], dp[2005][2005][2], floyd[305][305]; 23 24 int main() { 25 int n = read(), m = read(), v = read(), e = read(); 26 for (register int i = 1; i <= n; ++ i) c[i] = read(); 27 for (register int i = 1; i <= n; ++ i) d[i] = read(); 28 for (register int i = 1; i <= n; ++ i) scanf("%lf", &k[i]); 29 for (register int i = 1; i < v; ++ i) 30 for (register int j = i + 1; j <= v; ++ j) 31 floyd[i][j] = floyd[j][i] = INF; 32 for (register int i = 1; i <= e; ++ i) { 33 int u = read(), v = read(), w = read(); 34 floyd[u][v] = floyd[v][u] = fmin(floyd[u][v], w); 35 } 36 for (register int k = 1; k <= v; ++ k) 37 for (register int i = 1; i < v; ++ i) 38 for (register int j = i + 1; j <= v; ++ j) 39 if (floyd[i][j] > floyd[i][k] + floyd[k][j]) 40 floyd[i][j] = floyd[j][i] = floyd[i][k] + floyd[k][j]; 41 for (register int i = 1; i <= n; ++ i) 42 for (register int j = 0; j <= m; ++ j) 43 dp[i][j][0] = dp[i][j][1] = INF; 44 dp[1][0][0] = dp[1][1][1] = 0; 45 for (register int i = 2; i <= n; ++ i) { 46 for (register int j = 0; j <= m && j <= i; ++ j) { 47 dp[i][j][0] = fmin(dp[i-1][j][0] + floyd[c[i-1]][c[i]], 48 dp[i-1][j][1] + floyd[d[i-1]][c[i]] * k[i-1] 49 + floyd[c[i-1]][c[i]] * (1 - k[i-1])); 50 if (j == 0) continue; 51 dp[i][j][1] = fmin(dp[i-1][j-1][0] + floyd[c[i-1]][d[i]] * k[i] 52 + floyd[c[i-1]][c[i]] * (1 - k[i]), 53 dp[i-1][j-1][1] + floyd[d[i-1]][d[i]] * k[i-1] * k[i] 54 + floyd[d[i-1]][c[i]] * k[i-1] * (1 - k[i]) 55 + floyd[c[i-1]][d[i]] * (1 - k[i-1]) * k[i] 56 + floyd[c[i-1]][c[i]] * (1 - k[i-1]) * (1 - k[i])); 57 } 58 } 59 double ans = INF; 60 for (register int i = 0; i <= m; ++ i) 61 ans = fmin(ans, fmin(dp[n][i][0], dp[n][i][1])); 62 printf("%.2lf\n", ans); 63 return 0; 64 }

NOIP 2016 換教室 | 概率DP