【题目链接】
【算法】
概率DP
先跑一遍floyed,求出每个教室之间的最短路径,存在数组dist[][]中,时间复杂度O(V^3)
设计状态,f[i][j][k]表示当前选到第i个教室,已经选了j个教室,当前这个教室选不选(0..1)
那么,状态转移方程是什么呢?
假设当前选到第i个教室,已经选了j个教室,那么,如果不选这个教室,则状态转移方程为
f[i][j][0] = max{f[i-1][j][0]+dist[c[i-1]][c[i]],f[i-1][j][1]+dist[c[i-1]][c[i]]*(1-k[i-1])+dist[d[i-1]][c[i]]*k[i-1]}
如果选这个教室,则状态转移方程是
f[i][j][1] = min{f[i-1][j-1][0]+dist[c[i-1]][d[i]]*k[i]+dist[c[i-1]][c[i]]*(1-k[i],f[i-1][j-1][1]+dist[d[i-1]][d[i]]*k[i-1]*k[i]+dist[c[i-1]][d[i]]*(1-k[i-1])*k[i]+dist[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+dist[d[i-1]][c[i]]*k[i-1]*(1-k[i])}
于是这道题便迎刃而解了!
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 2000 #define MAXV 300 int i,j,k,n,m,v,e,a,b,w; int dist[MAXV+10][MAXV+10],c[MAXN+10],d[MAXN+10]; double P[MAXN+10],dp[MAXN+10][MAXN+10][2]; double ans = 2e9; template <typename T> inline void read(T &x) { int f=1; x=0; char c = getchar(); for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; } for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> inline void write(T x) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) write(x/10); putchar(x%10+'0'); } template <typename T> inline void writeln(T x) { write(x); puts(""); } int main() { read(n); read(m); read(v); read(e); for (i = 1; i <= v; i++) { for (j = 1; j <= v; j++) { if (i != j) dist[i][j] = 2e9; } } for (i = 1; i <= n; i++) read(c[i]); for (i = 1; i <= n; i++) read(d[i]); for (i = 1; i <= n; i++) cin >> P[i]; for (i = 1; i <= e; i++) { read(a); read(b); read(w); dist[a][b] = min(dist[a][b],w); dist[b][a] = min(dist[b][a],w); } for (k = 1; k <= v; k++) { for (i = 1; i <= v; i++) { if (i == k) continue; if (dist[i][k] == 2e9) continue; for (j = 1; j <= v; j++) { if (dist[k][j] == 2e9) continue; if ((i == j) || (k == j)) continue; dist[i][j] = min(dist[i][j],dist[i][k]+dist[k][j]); } } } for (i = 1; i <= n; i++) { for (j = 0; j <= m; j++) { dp[i][j][0] = dp[i][j][1] = 2e9; } } dp[1][0][0] = 0; dp[1][1][1] = 0; for (i = 2; i <= n; i++) { dp[i][0][0] = dp[i-1][0][0] + dist[c[i-1]][c[i]]; for (j = 1; j <= min(i,m); j++) { dp[i][j][0] = min(dp[i-1][j][0]+dist[c[i-1]][c[i]],dp[i-1][j][1]+dist[c[i-1]][c[i]]*(1.0-P[i-1])+dist[d[i-1]][c[i]]*P[i-1]); dp[i][j][1] = min(dp[i-1][j-1][0]+dist[c[i-1]][d[i]]*P[i]*1.0+dist[c[i-1]][c[i]]*(1.0-P[i]), dp[i-1][j-1][1]+ dist[d[i-1]][d[i]]*P[i-1]*P[i]*1.0+ dist[c[i-1]][d[i]]*(1.0-P[i-1])*P[i]+ dist[c[i-1]][c[i]]*(1.0-P[i-1])*(1.0-P[i])+ dist[d[i-1]][c[i]]*P[i-1]*(1-P[i])*1.0); } } for (i = 0; i <= m; i++) ans = min(ans,min(dp[n][i][0],dp[n][i][1])); cout<< fixed << setprecision(2) << ans << endl; return 0; }