设 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 }