【一本通】虫洞
- C语言代码
- C++代码
- JAVA代码
💐The Begin💐点点关注,收藏不迷路💐
|
John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。John的每个农场有M条小路(无向边)连接着N (从1…N标号)块地,并有W个虫洞(有向边)。其中1<=N<=500,1<=M<=2500,1<=W<=200。 现在John想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。 John将向你提供F(1<=F<=5)个农场的地图。没有小路会耗费你超过10000秒的时间,当然也没有虫洞回帮你回到超过10000秒以前。
输入
第1行: 一个整数 F, 表示农场个数。
每个农场的第1行:三个整数 N, M, W。
每个农场的第2…M + 1行:三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条用时T秒的小路。
每个农场的M + 2…M + W + 1行: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条可以使John到达T秒前的虫洞。
输出
第1至F行: 如果John能在这个农场实现他的目标,输出"YES",否则输出"NO"。
样例输入
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
样例输出
NO
YES
C语言代码
#include <stdio.h>
#include <stdlib.h>
#define INF 0x3f3f3f3f
#define MAXN 500 + 5
// 边结构体,存储边的起点、终点和权重(时间花费,虫洞时为负权重)
typedef struct Edge {
int from;
int to;
int weight;
} Edge;
// Bellman-Ford算法判断是否存在负权环(存在负权环则能回到过去)
int bellmanFord(int n, Edge edges[], int edgeCount) {
int dist[MAXN];
for (int i = 1; i <= n; ++i) {
dist[i] = INF;
}
dist[1] = 0;
for (int i = 1; i <= n; ++i) {
int updated = 0;
for (int j = 0; j < edgeCount; ++j) {
if (dist[edges[j].to] > dist[edges[j].from] + edges[j].weight) {
dist[edges[j].to] = dist[edges[j].from] + edges[j].weight;
updated = 1;
}
}
if (!updated) {
return 0;
}
}
return 1;
}
int main() {
int F;
scanf(“%d”, &F);
while (F–) {
int N, M, W;
scanf(“%d %d %d”, &N, &M, &W);
Edge* edges = (Edge*)malloc((2 M + W) sizeof(Edge));
int edgeIndex = 0;
// 读入无向边(小路)信息,转换为两条有向边存入edges
for (int i = 0; i < M; ++i) {
int S, E, T;
scanf(“%d %d %d”, &S, &E, &T);
edges[edgeIndex++] = (Edge){S, E, T};
edges[edgeIndex++] = (Edge){E, S, T};
}
// 读入有向边(虫洞)信息,存入edges
for (int i = 0; i < W; ++i) {
int S, E, T;
scanf(“%d %d %d”, &S, &E, &T);
edges[edgeIndex++] = (Edge){S, E, -T};
}
int canGoBack = bellmanFord(N, edges, edgeIndex);
printf(“%s\n”, canGoBack? “YES” : “NO”);
free(edges);
}
return 0;
}
C++代码
#include <iostream
>
#include <vector
>
#include <cstring
>
using namespace std;
const int INF = 0x3f3f3f3f; // 定义一个很大的值,用于初始化距离等情况
const int MAXN = 500 + 5; // 节点数量上限,题目给定范围加一些余量
// 边结构体,用于存储边的起点、终点和权重(时间花费,虫洞时为负权重)
struct Edge {
int from;
int to;
int weight;
};
// 使用Bellman-Ford算法判断是否存在负权环(存在负权环则能回到过去)
bool bellmanFord(int n, vector& edges) {
vector dist(n + 1, INF); // 存储从源点到各节点的距离,初始化为很大值
dist[1] = 0; // 可以任意设置一个起始点距离为0,因为要检测整个图是否有负环
for (int i = 1; i <= n; ++i) { // 进行n次迭代(理论上n - 1次就够,但多一次可检测负权环)
bool updated = false; // 标记本轮是否有距离更新
for (Edge edge : edges) { // 遍历所有边
if (dist[edge.to] > dist[edge.from] + edge.weight) { // 尝试松弛操作
dist[edge.to] = dist[edge.from] + edge.weight;
updated = true;
}
}
if (!updated) { // 如果本轮没有距离更新,说明已经收敛,不存在负权环,提前退出
return false;
}
}
return true; // 如果完成n次迭代后仍能更新距离,说明存在负权环,即能回到过去
}
int main() {
int F;
cin >> F; // 读入农场个数
while (F–) { // 对每个农场进行处理
int N, M, W;
cin >> N >> M >> W; // 读入该农场的节点数、无向边(小路)数量、有向边(虫洞)数量
vector edges; // 存储该农场的所有边信息
// 读入无向边(小路)信息,将其转换为两条有向边存入edges
for (int i = 0; i < M; ++i) {
int S, E, T;
cin >> S >> E >> T;
edges.push_back({S, E, T});
edges.push_back({E, S, T});
}
// 读入有向边(虫洞)信息,存入edges
for (int i = 0; i < W; ++i) {
int S, E, T;
cin >> S >> E >> T;
edges.push_back({S, E, -T}); // 虫洞权重为负,表示回到过去,时间减少
}
bool canGoBack = bellmanFord(N, edges); // 判断该农场是否能回到过去
cout << (canGoBack? “YES” : “NO”) << endl; // 根据结果输出相应字符串
}
return 0;
}
JAVA代码
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
class Edge {
int from; // 边的起点
int to; // 边的终点
int weight; // 边的权重(时间花费,虫洞时为负权重)
public Edge(int from, int to, int weight) {
this.from = from;
this.to = to;
this.weight = weight;
}
}
public class Main {
private static final int INF = 0x3f3f3f3f; // 定义一个很大的值,用于初始化距离等情况
private static final int MAXN = 500 + 5; // 节点数量上限,题目给定范围加一些余量
// 使用Bellman-Ford算法判断是否存在负权环(存在负权环则能回到过去)
private static boolean bellmanFord(int n, List edges) {
int[] dist = new int[n + 1];
for (int i = 1; i <= n; i++) {
dist[i] = INF;
}
dist[1] = 0;
for (int i = 1; i <= n; i++) { // 进行n次迭代(理论上n - 1次就够,但多一次可检测负权环)
boolean updated = false; // 标记本轮是否有距离更新
for (Edge edge : edges) { // 遍历所有边
if (dist[edge.to] > dist[edge.from] + edge.weight) { // 尝试松弛操作
dist[edge.to] = dist[edge.from] + edge.weight;
updated = true;
}
}
if (!updated) { // 如果本轮没有距离更新,说明已经收敛,不存在负权环,提前退出
return false;
}
}
return true; // 如果完成n次迭代后仍能更新距离,说明存在负权环,即能回到过去
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int F = scanner.nextInt(); // 读入农场个数
for (int f = 0; f < F; f++) { // 对每个农场进行处理
int N = scanner.nextInt(); // 读入该农场的节点数
int M = scanner.nextInt(); // 读入该农场的无向边(小路)数量
int W = scanner.nextInt(); // 读入该农场的有向边(虫洞)数量
List edges = new ArrayList<>();
// 读入无向边(小路)信息,将其转换为两条有向边存入edges
for (int i = 0; i < M; i++) {
int S = scanner.nextInt();
int E = scanner.nextInt();
int T = scanner.nextInt();
edges.add(new Edge(S, E, T));
edges.add(new Edge(E, S, T));
}
// 读入有向边(虫洞)信息,存入edges
for (int i = 0; i < W; i++) {
int S = scanner.nextInt();
int E = scanner.nextInt();
int T = scanner.nextInt();
edges.add(new Edge(S, E, -T)); // 虫洞权重为负,表示回到过去,时间减少
}
boolean canGoBack = bellmanFord(N, edges); // 判断该农场是否能回到过去
System.out.println(canGoBack? “YES” : “NO”); // 根据结果输出相应字符串
}
scanner.close();
}
}
💐The End💐点点关注,收藏不迷路💐
|