题目
题
目
传
送
门
\color{red}{题目传送门}
题目传送门
输入输出样例
输入样例
3 2 3 3
2 1 2
1 2 1
0.8 0.2 0.5
1 2 5
1 3 3
2 3 1
输出样例
2.80
题解
这题真的水,第一次写DP一眼看出方程式qaq- 声明:
1. c [ i ] c[i] c[i]为原来上课的教室, d [ i ] d[i] d[i]为换后的教室
2. p [ i ] p[i] p[i]表示换成功的概率
3. r [ i ] [ j ] r[i][j] r[i][j]表示 i , j i,j i,j两点之间的距离
4. f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示当前选到了第 i i i个时间段,已经换了 j j j次教室,当前时间段是否换教室( k = 0 k = 0 k=0或 1 1 1, 0 0 0表示不选, 1 1 1表示选)所获得的最小期望
5. { p [ i − 1 ] ∗ r [ d [ i − 1 ] ] [ c [ i ] ] i − 1 换 课 成 功 ( 1 − p [ i − 1 ] ) ∗ r [ c [ i − 1 ] ] [ c [ i ] ] i − 1 换 课 失 败 \begin{cases}p[i-1]*r[d[i-1]][c[i]] & i-1换课成功\\ (1-p[i-1])*r[c[i-1]][c[i]] & i-1换课失败\end{cases} {p[i−1]∗r[d[i−1]][c[i]](1−p[i−1])∗r[c[i−1]][c[i]]i−1换课成功i−1换课失败
其他情况同理可得 - 状态转移
∙ \bullet ∙ 若当前没有换教室
f [ i ] [ j ] [ 0 ] = { f [ i − 1 ] [ j ] [ 1 ] + p [ i − 1 ] ∗ r [ d [ i − 1 ] ] [ c [ i ] ] + ( 1 − p [ i − 1 ] ) ∗ ( r [ c [ i − 1 ] ] [ c [ i ] ] ) f [ i − 1 ] [ j ] [ 0 ] + r [ c [ i − 1 ] ] [ c [ i ] ] f[i][j][0] = \begin{cases}f[i-1][j][1]+p[i-1]*r[d[i-1]][c[i]]+(1-p[i-1])*(r[c[i-1]][c[i]]) \\ f[i-1][j][0]+r[c[i-1]][c[i]]\end{cases} f[i][j][0]={f[i−1][j][1]+p[i−1]∗r[d[i−1]][c[i]]+(1−p[i−1])∗(r[c[i−1]][c[i]])f[i−1][j][0]+r[c[i−1]][c[i]]
∙ \bullet ∙ 若当前换教室
a = p [ i − 1 ] ∗ p [ i ] ∗ r [ d [ i − 1 ] ] [ d [ i ] ] a= p[i-1] * p[i] * r[d[i-1]][d[i]] a=p[i−1]∗p[i]∗r[d[i−1]][d[i]] 第 i − 1 i-1 i−1和 i i i都换课成功
b = ( 1 − p [ i − 1 ] ) ∗ p [ i ] ∗ r [ c [ i − 1 ] ] [ d [ i ] ] b=(1 - p[i-1]) * p[i] * r[c[i-1]][d[i]] b=(1−p[i−1])∗p[i]∗r[c[i−1]][d[i]] 第 i − 1 i-1 i−1个失败第 i i i个成功
c = p [ i − 1 ] ∗ ( 1 − p [ i ] ) ∗ r [ d [ i − 1 ] ] [ c [ i ] ] c=p[i-1] * (1 - p[i]) * r[d[i-1]][c[i]] c=p[i−1]∗(1−p[i])∗r[d[i−1]][c[i]] 第 i − 1 i-1 i−1个成功第 i − 1 i-1 i−1个失败
d = ( 1 − p [ i − 1 ] ) ∗ ( 1 − p [ i ] ) ∗ r [ c [ i − 1 ] ] [ c [ i ] ] d=(1 - p[i-1]) * (1 - p[i]) * r[c[i-1]][c[i]] d=(1−p[i−1])∗(1−p[i])∗r[c[i−1]][c[i]] 第 i − 1 i-1 i−1和第 i i i个都失败
f [ i ] [ j ] [ 1 ] = { f [ i − 1 ] [ j − 1 ] [ 1 ] + a + b + c + d f [ i − 1 ] [ j − 1 ] [ 0 ] + p [ i ] ∗ r [ c [ i − 1 ] ] [ d [ i ] ] + ( 1 − p [ i ] ) ∗ r [ c [ i − 1 ] ] [ c [ i ] ] f[i][j][1] = \begin{cases}f[i-1][j-1][1] + a + b +c + d \\ f[i-1][j-1][0] + p[i] * r[c[i-1]][d[i]] + (1 - p[i]) * r[c[i-1]][c[i]]\end{cases} f[i][j][1]={f[i−1][j−1][1]+a+b+c+df[i−1][j−1][0]+p[i]∗r[c[i−1]][d[i]]+(1−p[i])∗r[c[i−1]][c[i]]
c o d e code code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e3 + 100;
const int inf = 0x3f3f3f3f;
template <typename T>
inline void read(T &s) {
s = 0;
T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s<<1) + (s<<3) + (ch^48); ch = getchar(); }
s *= w;
}
int n, m, v, e;
int c[maxn], d[maxn];
int r[maxn][maxn];
double f[maxn][maxn][2];
double p[maxn];
inline void floyd() {
for (int k = 1; k <= v; ++k)
for (int i = 1; i <= v; ++i)
for (int j = 1; j < v; ++j)
if (r[i][j] > r[i][k] + r[k][j])
r[j][i] = r[i][j] = r[i][k] + r[k][j];
}
inline void dp() {
for (int i = 1; i <= n; ++i)
for (int j = 0; j <= m; ++j)
for (int k = 0; k <= 1; ++k)
f[i][j][k] = 123456789.66;
f[1][0][0] = 0.00;
f[1][1][1] = 0.00;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
double x = f[i-1][j][1] + p[i-1] * r[d[i-1]][c[i]] + (1 - p[i-1]) * r[c[i-1]][c[i]];
double y = f[i-1][j][0] + r[c[i-1]][c[i]];
f[i][j][0] = min(x, y);
if (j) {
x = f[i-1][j-1][1] + p[i-1] * p[i] * r[d[i-1]][d[i]] + (1 - p[i-1]) * p[i] * r[c[i-1]][d[i]] + p[i-1] * (1 - p[i]) * r[d[i-1]][c[i]] + (1 - p[i-1]) * (1 - p[i]) * r[c[i-1]][c[i]];
y = f[i-1][j-1][0] + p[i] * r[c[i-1]][d[i]] + (1 - p[i]) * r[c[i-1]][c[i]];
f[i][j][1] = min(x, y);
}
}
}
}
int main() {
read(n), read(m), read(v), read(e);
for (int i = 1; i <= n; ++i) read(c[i]);
for (int i = 1; i <= n; ++i) read(d[i]);
for (int i = 1; i <= n; ++i) scanf("%lf", &p[i]);
for (int i = 1; i <= v; ++i)
for (int j = 1; j < i; ++j)
r[i][j] = r[j][i] = inf;
for (int i = 1; i <= e; ++i) {
int x, y, z;
read(x), read(y), read(z);
r[x][y] = min(r[x][y], z);
r[y][x] = r[x][y];
}
floyd();
dp();
double ans = 123456789.66;
for (int i = 0; i <= m; ++i)
for (int j = 0; j <= 1; ++j)
ans = min(ans, f[n][i][j]);
printf("%.2lf\n", ans);
return 0;
}