P1850 [NOIP2016 提高组] 换教室
[NOIP2016 提高组] 换教室
题目描述
对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程。
在可以选择的课程中,有
在不提交任何申请的情况下,学生们需要按时间段的顺序依次完成所有的
由于更换教室的需求太多,申请不一定能获得通过。通过计算,牛牛发现申请更换第
学校规定,所有的申请只能在学期开始前一次性提交,并且每个人只能选择至多
因为不同的课程可能会被安排在不同的教室进行,所以牛牛需要利用课间时间从一间教室赶到另一间教室。
牛牛所在的大学有
现在牛牛想知道,申请哪几门课程可以使他因在教室间移动耗费的体力值的总和的期望值最小,请你帮他求出这个最小值。
输入格式
第一行四个整数
第二行
第三行
第四行
接下来
保证
保证通过学校里的道路,从任何一间教室出发,都能到达其他所有的教室。
保证输入的实数最多包含
输出格式
输出一行,包含一个实数,四舍五入精确到小数点后恰好
测试数据保证四舍五入后的答案和准确答案的差的绝对值不大于
样例 #1
样例输入 #1
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
样例输出 #1
2.80
提示
【样例1说明】
所有可行的申请方案和期望收益如下表:
【提示】
- 道路中可能会有多条双向道路连接相同的两间教室。 也有可能有道路两端连接的是同一间教室。
- 请注意区分n,m,v,e的意义, n不是教室的数量, m不是道路的数量。
特殊性质1:图上任意两点
特殊性质2:对于所有的
Solution
期望
可以发现这道题与最短路是相关的,并且点数的规模只有
设
先考虑
可以发现
-
上一个换,换成功了:
-
上一个换,换失败了:
-
上一个不换:
对于
-
上一个不换,当前这个换,换成功了:
-
上一个不换,当前这个换,换失败了:
-
上一个换,换成功了,当前这个换,换成功了:
-
上一个换,换成功了,当前这个换,换失败了:
-
上一个换,换失败了,当前这个换,换成功了:
-
上一个换,换失败了,当前这个换,换失败了:
完整代码
需要注意 Floyd 的自环不能赋值为
#include<bits/stdc++.h>
using namespace std;
int dis[305][305];
constexpr int _SIZE = 2e3;
int n, m, v, e;
int c[_SIZE + 5], d[_SIZE + 5];
double k[_SIZE + 5];
double f[2][_SIZE + 5];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n >> m >> v >> e;
memset(dis, 0x3f, sizeof dis);
for (int i = 1; i <= n; i++) cin >> c[i];
for (int i = 1; i <= n; i++) cin >> d[i];
for (int i = 1; i <= n; i++) cin >> k[i];
for (int i = 1; i <= v; i++) dis[i][i] = 0;
for (int i = 1; i <= e; i++) {
int u, v, l;
cin >> u >> v >> l;
int temp = min(dis[u][v], l);
dis[u][v] = dis[v][u] = temp;
}
for (int k = 1; k <= v; k++)
for (int i = 1; i <= v; i++)
for (int j = 1; j <= v; j++)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
memset(f, 127, sizeof f);
f[0][0] = 0, f[1][1] = 0;
for (int i = 2; i <= n; i++) {
for (int j = i; j >= 0; j--) {
f[0][j] = min(f[1][j] + k[i - 1] * dis[d[i - 1]][c[i]] +
(1 - k[i - 1]) * dis[c[i - 1]][c[i]],
f[0][j] + dis[c[i - 1]][c[i]]);
if (j == 0) continue;
f[1][j] = min(f[0][j - 1] + k[i] * dis[c[i - 1]][d[i]] +
(1 - k[i]) * dis[c[i - 1]][c[i]],
f[1][j - 1] + k[i - 1] * k[i] * dis[d[i - 1]][d[i]] +
k[i - 1] * (1 - k[i]) * dis[d[i - 1]][c[i]] +
(1 - k[i - 1]) * k[i] * dis[c[i - 1]][d[i]] +
(1 - k[i - 1]) * (1 - k[i]) * dis[c[i - 1]][c[i]]);
}
}
double ans = 1145141919810.0;
for (int i = 0; i <= m; i++) ans = min({ans, f[0][i], f[1][i]});
cout << fixed << setprecision(2) << ans << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步