UVALive - 4618 Wormholes(负环)
2015-08-21 00:15
405 查看
题目大意:给出出发点和终点和m个虫洞(虫洞的出发点,终点,生成时间和花费时间),问从起点到终点花费的最小时间
解题思路:关键是有负环,所以直接跑最短路算法的话会TLE,所以负环要处理一下
但是这个负环又不是负环,因为负环到一定程度的话,就会消失。
比如,到达时间小于虫洞的生成时间,那么负环就消失了,也就是说,负环内的点满足的最优情况就是到达时间刚好等于生成时间
所以,先找出负环,接着判断一下这个负环内的能节省的最多时间,然后将所有点都减去那个时间,那么负环就消失了
具体看代码
解题思路:关键是有负环,所以直接跑最短路算法的话会TLE,所以负环要处理一下
但是这个负环又不是负环,因为负环到一定程度的话,就会消失。
比如,到达时间小于虫洞的生成时间,那么负环就消失了,也就是说,负环内的点满足的最优情况就是到达时间刚好等于生成时间
所以,先找出负环,接着判断一下这个负环内的能节省的最多时间,然后将所有点都减去那个时间,那么负环就消失了
具体看代码
[code]#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 110 #define INF 0x3f3f3f3f struct Point{ int x, y, z; }s1, s2; struct wormhole{ Point s, t; int start, cost; }W ; int n, source, sink; int dis ; int distance(int i, int j) { int x = W[i].t.x - W[j].s.x; int y = W[i].t.y - W[j].s.y; int z = W[i].t.z - W[j].s.z; return ceil(sqrt(1.0 * x * x + 1.0 * y * y + 1.0 * z * z)); } void init() { scanf("%d%d%d%d%d%d%d", &s1.x, &s1.y, &s1.z, &s2.x, &s2.y, &s2.z, &n); source = 0; sink = n + 1; W[0].s = s1; W[0].t = s1; W[0].start = -INF; W[0].cost = 0; W[sink].s = s2; W[sink].t = s2; W[sink].start =-INF; W[sink].cost = 0; for (int i = 1; i <= n; i++) scanf("%d%d%d%d%d%d%d%d", &W[i].s.x, &W[i].s.y, &W[i].s.z, &W[i].t.x, &W[i].t.y, &W[i].t.z, &W[i].start, &W[i].cost); //dis[i][j]表示从第i个虫洞的终点走到第j个虫洞的出发点的时间 for (int i = 0; i <= sink; i++) for (int j = 0; j <= sink; j++) dis[i][j] = distance(i, j); } int pre , d ; void solve() { for (int i = 0; i <= sink; i++) { d[i] = INF; pre[i] = -1; } d[source] = 0; while (1) { int tmp; bool flag = false; //找最短路 for (int i = 0; i <= sink; i++) for (int j = 0; j <= sink; j++) { tmp = max(d[i] + dis[i][j], W[j].start) + W[j].cost; if (tmp < d[j]) { d[j] = tmp; pre[j] = i; flag = true; } } //不用更新了 if (!flag) { printf("%d\n", d[sink]); return ; } for (int i = 0; i <= sink; i++) { int k = i; //判断有没有环 for (int j = 0; j <= sink && k != -1; j++) k = pre[k]; if (k == -1) continue; //找出更新的值,破除这个负环,更新的值就是到达起点的值和生成时间的差的最小值,因为在负环内可以等待到生成时间 int Min = d[pre[k]] + dis[pre[k]][k] - W[k].start; for (int j = pre[k]; j != k; j = pre[j]) Min = min(d[pre[j]] + dis[pre[j]][j] - W[j].start, Min); //如果不存在负环了 if (Min <= 0) continue; //更新负环内的点的距离,破解负环 d[k] -= Min; for (int j = pre[k]; j != k; j = pre[j]) d[j] -= Min; } } } int main() { int test; scanf("%d", &test); while (test--) { init(); solve(); } return 0; }
相关文章推荐
- 七夕与Gulp的第一次!
- 数据结构List
- 有关Apache Ignite的peer class loading (P2P class loading)
- STM32的精确延时
- spring boot
- PHP中正则表达式学习及应用(三)
- Fabonacci 数列
- java连接数据库时出现如下错误:
- C语言内存分配
- 本人对数据结构的理解,希望对大家有所帮助
- Python:insert排序算法
- 欢迎使用CSDN-markdown编辑器
- Struts2入门示例教程
- 题目:N皇后问题
- 第一百四十天 how can I坚持
- 微信开发相关图书推荐
- 将要和正在读的软件架构书
- android ListView向上滑动隐藏标题,下拉显示标题栏
- 题目:nuts 和 bolts 的问题
- Android开发菜鸟到高手必备的十本畅销书籍