农场虫洞问题

x33g5p2x  于2022-07-10 转载在 其他  
字(2.3k)|赞(0)|评价(0)|浏览(256)

一 原问题链接

Wormholes - POJ 3259 - Virtual Judge

https://vjudge.net/problem/POJ-3259

二 输入和输出

1 输入

第1行是单个整数 F,表示农场的数量。每个农场的第 1 行有3个整数N、M、W,表示编号为1~N块田,M 条路径和 W 个虫洞。第 2~M+1 行,每行都包含 3 个数字 S、E、T,表示穿过 S 与 E 之间的路径(双向)需要 T 秒。第 M+2~M+W+1 行,每行都包含 3 个数字 S、E、T,表示对从 S 到 E 的单向路径,旅行者将穿越 T 秒。

2 输出

对于每个农场,如果约翰可以达到目标,则输出“YES”,否则输出“NO”。

三 输入和输出样例

1 输入样例

2

3 3 1

1 2 2

1 3 4

2 3 1

3 1 3

3 2 1

1 2 3

2 3 4

3 1 8

 2 输出样例

NO

YES

四 分析

1 样例一分析

约翰无法在他出发之前的时间返回。

2 样例二分析

约翰可以在 1 > 2 > 3 > 1 的周期内及时返回,在他离开前1秒返回他的起始位置。他可以从周期内任何位置开始实行这一目标。因为存在一个负环(边权之和为负)1 > 2 > 3 > 1,边权之和为 -1。

五 算法设计

本问题其实就是判断是否有负环,使用 SPFA 判断负环即可。

注意:普通道路是双向的,虫洞是单向的,而且时间为负值。

六 代码

  1. package graph.poj3259;
  2. import java.util.LinkedList;
  3. import java.util.Queue;
  4. import java.util.Scanner;
  5. public class Poj3259 {
  6. static final int maxn = 505;
  7. static final int maxe = 100001;
  8. static final int inf = 0x3f3f3f3f;
  9. static int T;
  10. static int n;
  11. static int m;
  12. static int w;
  13. static int cnt;
  14. static node e[] = new node[maxe];
  15. static int head[] = new int[maxn];
  16. static int dis[] = new int[maxn];
  17. static int sum[] = new int[maxn];
  18. // 标记是否在队列中
  19. static boolean vis[] = new boolean[maxn];
  20. static {
  21. for (int i = 0; i < e.length; i++) {
  22. e[i] = new node();
  23. }
  24. }
  25. static void add(int u, int v, int c) {
  26. e[cnt].to = v;
  27. e[cnt].next = head[u];
  28. e[cnt].c = c;
  29. head[u] = cnt++;
  30. }
  31. static boolean spfa(int u) {
  32. Queue<Integer> q = new LinkedList<>();
  33. for (int i = 0; i < vis.length; i++) {
  34. vis[i] = false;
  35. }
  36. // 统计入队的次数
  37. for (int i = 0; i < sum.length; i++) {
  38. sum[i] = 0;
  39. }
  40. vis[u] = true;
  41. dis[u] = 0;
  42. sum[u]++;
  43. q.add(u);
  44. while (!q.isEmpty()) {
  45. int x = q.peek();
  46. q.poll();
  47. vis[x] = false;
  48. for (int i = head[x]; i != -1; i = e[i].next) {
  49. if (dis[e[i].to] > dis[x] + e[i].c) {
  50. dis[e[i].to] = dis[x] + e[i].c;
  51. if (!vis[e[i].to]) {
  52. if (++sum[e[i].to] >= n)
  53. return false;
  54. vis[e[i].to] = true;
  55. q.add(e[i].to);
  56. }
  57. }
  58. }
  59. }
  60. return true;
  61. }
  62. static boolean solve() {
  63. for (int i = 0; i < dis.length; i++) {
  64. dis[i] = inf;
  65. }
  66. for (int i = 1; i <= n; i++)
  67. if (dis[i] == inf) // 如果已经到达该点没找到负环,则不需要再从该点找
  68. if (!spfa(i))
  69. return true;
  70. return false;
  71. }
  72. public static void main(String[] args) {
  73. Scanner scanner = new Scanner(System.in);
  74. T = scanner.nextInt();
  75. while (T-- > 0) {
  76. cnt = 0;
  77. n = scanner.nextInt();
  78. m = scanner.nextInt();
  79. w = scanner.nextInt();
  80. for (int i = 0; i < head.length; i++) {
  81. head[i] = -1;
  82. }
  83. int u, v, t;
  84. for (int i = 1; i <= m; i++) {
  85. u = scanner.nextInt();
  86. v = scanner.nextInt();
  87. t = scanner.nextInt();
  88. add(u, v, t); // 两条边
  89. add(v, u, t);
  90. }
  91. for (int i = 1; i <= w; i++) {
  92. u = scanner.nextInt();
  93. v = scanner.nextInt();
  94. t = scanner.nextInt();
  95. add(u, v, -t); // 一条边
  96. }
  97. if (solve())
  98. System.out.println("YES");
  99. else
  100. System.out.println("NO");
  101. }
  102. }
  103. }
  104. class node {
  105. int to;
  106. int c;
  107. int next;
  108. }

七 测试

相关文章