题意
有个独立的时间段,每个时间段有2节课对应两个教室,一开始被安排上的课,但你可以申请换课,换课申请提交后有概率成功换课.有个教室,也就是说每节课你需要花时间到指定教室,你想要提交一些申请,使你期望走过的距离和最小.需要注意的是,申请次数有上限.
数据范围:(为连接教室的边的数量,为双向边)
题解
首先可以知道,需要处理出两两之间的最短路
然后就是申请的问题
如果没有概率那么就是很明显的一个
状态为,节课时提交了个申请且第节课是否提交申请的最小值
如果加入了概率可以看到其实也是成立的,不过要考虑时如果申请是否申请成功即可
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 5e6 + 5;
int N, M, V, E;
int c[2005], d[2005];
double p[2005];
int dis[305][305];
double dp[2005][2005][2];
int main(){
int i, j, k;
scanf("%d%d%d%d", &N, &M, &V, &E);
for(i = 1; i <= N; i++) scanf("%d", c + i);
for(i = 1; i <= N; i++) scanf("%d", d + i);
for(i = 1; i <= N; i++) scanf("%lf", p + i);
memset(dis, 60, sizeof(dis));
for(i = 1; i <= E; i++){
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
dis[x][y] = dis[y][x] = min(dis[x][y], w);
}
for(i = 1; i <= V; i++) dis[i][i] = 0;
for(k = 1; k <= V; k++)
for(i = 1; i <= V; i++)
for(j = i + 1; j <= V; j++)
if(dis[i][j] > dis[i][k] + dis[k][j])
dis[i][j] = dis[j][i] = dis[i][k] + dis[k][j];
int top;
for(i = 1; i <= N; i++)
for(j = 0; j <= M; j++) dp[i][j][1] = dp[i][j][0] = 1e9;
dp[1][0][0] = dp[1][1][1] = 0;
for(i = 2; i <= N; i++)
for(j = 0, top = min(i, M); j <= top; j++){
if(j){
dp[i][j][1] = min(dp[i - 1][j - 1][0] +
p[i] * dis[c[i - 1]][d[i]] +
(1 - p[i]) * dis[c[i - 1]][c[i]],
dp[i - 1][j - 1][1] +
p[i - 1] * p[i] * dis[d[i - 1]][d[i]] +
(1 - p[i - 1]) * p[i] * dis[c[i - 1]][d[i]] +
p[i - 1] * (1 - p[i]) * dis[d[i - 1]][c[i]] +
(1 - p[i - 1]) * (1 - p[i]) * dis[c[i - 1]][c[i]]);
dp[i][j][0] = min(dp[i - 1][j][0] +
dis[c[i - 1]][c[i]],
dp[i - 1][j][1] +
p[i - 1] * dis[d[i - 1]][c[i]] +
(1 - p[i - 1]) * dis[c[i - 1]][c[i]] );
}else{
dp[i][j][0] = dp[i - 1][j][0] + dis[c[i - 1]][c[i]];
}
}
double ans = 1e9;
for(i = 0, top = min(N, M); i <= top; i++) ans = min(ans, min(dp[N][i][1], dp[N][i][0]));
printf("%.2lf\n", ans);
return 0;
}