D
e
s
c
r
i
p
t
i
o
n
\color{blue}{Description}
Description
While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ’s farms comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1…N, M (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.
As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself 😃 .
To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000 seconds.
I
n
p
u
t
\color{blue}{Input}
Input
Line 1: A single integer, F. F farm descriptions follow.
Line 1 of each farm: Three space-separated integers respectively: N, M, and W
Lines 2…M+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected by more than one path.
Lines M+2…M+W+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.
O
u
t
p
u
t
\color{blue}{Output}
Output
Lines 1…F: For each farm, output “YES” if FJ can achieve his goal, otherwise output “NO” (do not include the quotes).
题意
有个农民有n块田。给你m组田与田间的距离关系(双向的)。再给你w组虫洞间的关系(可以把你送回到t秒前的位置的)。判断是否能利用虫洞回到出发地。
分析
用spfa判有无负环。如果有负环存在,表明肯定能穿越回到出发点。
import java.io.BufferedInputStream;
import java.util.Scanner;
/*
*
输入:
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 //虫洞路径 起点 终点 权值(记得,事实上市负的)
*
* */
public class POJ3259 {
static int M = 6000, N = 500 + 20, Inf = 1000000000 + 10;//M设这么大是因为m是双向的。
static edge_3295 e[] = new edge_3295[M];
static void start() {
for (int i = 0; i < M; i++) {
e[i] = new edge_3295();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int d[] = new int[N];
start();
Scanner sc = new Scanner(new BufferedInputStream(System.in));
int F = sc.nextInt();
int n, m, w, s, t, l, top;
while (F-- != 0) {//有多少组数据,while 循环读入
//要读入的数据有规律 第一行是 图的节点数 和 边数,但是注意咯 ,这里的边都是可以往返的,所以咯有了下面的
top = 0;
n = sc.nextInt();
m = sc.nextInt();
w = sc.nextInt();
for (int i = 0; i < m; i++) {
s = sc.nextInt();
t = sc.nextInt();
l = sc.nextInt();
e[top++].set(s, t, l);//注意咯上面说的下面 是这里
e[top++].set(t, s, l);//这里对 s 和 t or t和s 进行了两次保存,就是因为线路是可以反向的
}
for (int i = 0; i < w; i++) {
s = sc.nextInt();
t = sc.nextInt();
l = sc.nextInt();
e[top++].set(s, t, -l);
}
if (Bellman_Ford(n, top, d, 0, e)) {
System.out.println("NO");
} else {
System.out.println("YES");
}
}
}
private static boolean Bellman_Ford(int n, int m, int[] d, int s, edge_3295[] e) {//Bellman_Ford 核心代码,模板
// TODO Auto-generated method stub
for (int i = 0; i <= n; i++) {
d[i] = Inf;
}
d[s] = 0;
int check;
for (int i = 0; i < n - 1; i++) {
check = 0;
for (int j = 0; j < m; j++) {
if (d[e[j].t] > d[e[j].s] + e[j].l) {
d[e[j].t] = d[e[j].s] + e[j].l;
check=1;
}
}
if (check == 0) {
break;
}
}
for (int i = 0; i < m; i++) {
if (d[e[i].t] > d[e[i].s] + e[i].l) {
return false;
}
}
return true;
}
}
class edge_3295 {
int s;
int t;
int l;
public void set(int _s, int _t, int _l) {
this.s = _s;
this.t = _t;
this.l = _l;
}
}
/*
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
* */
// static StreamTokenizer sc=new StreamTokenizer(new BufferedInputStream(System.in));
// static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
// public static int nextInt()throws IOException {
// sc.nextToken();return (int)sc.nval;
// }
// public static long nextLong() throws IOException{sc.nextToken();return (long)sc.nval;}
//runtime error
import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Scanner;
public class Main{
/* [8.3~8.9]最小生成树
* */
static final int MAX_N=(int)6e4+5;
static final int INF=(int)1e6;
static int []dis,p;
static int n,eid;
static boolean []vis;
static edge e[];
public static void main(String[] args) {
Scanner sc=new Scanner(new BufferedInputStream(System.in));
int F=sc.nextInt();
int N,M,W;
while(F-->0) {
mapinit();
N=sc.nextInt();
M=sc.nextInt();
W=sc.nextInt();
int u,v,w;
while(M-->0) {
u=sc.nextInt();v=sc.nextInt();w=sc.nextInt();
insert2(u,v,w);
}
while(W-->0) {
u=sc.nextInt();v=sc.nextInt();w=sc.nextInt();
insert(u,v,-w);
}
if(check(N)) System.out.println("YES");
else System.out.println("NO");
}
}
static boolean SPFA(int x) {
vis[x]=true;
for(int i=p[x];i!=-1;i=e[i].next) {
int v=e[i].v,w=e[i].w;
if(dis[v]>dis[x]+w) {
dis[v]=dis[x]+w;
if(vis[v]) {
vis[x]=false;return true;
}else {
vis[x]=false;return true;
}
}
}
return vis[x]=false;
}
static boolean check(int n) {
Arrays.fill(dis, 0);
for(int i=1;i<=n;i++) if(SPFA(i)) return true;
return false;
}
static void insert(int u,int v,int w) {
e[eid].v=v;
e[eid].w=w;
e[eid].next=p[u];
p[u]=eid++;
}
static void insert2(int u,int v,int w) {
insert(u,v,w);
insert(v,u,w);
}
static void mapinit() {
Arrays.fill(p, -1);
Arrays.fill(vis, false);
eid=0;
}
static void init() {
p=new int [MAX_N];
dis=new int [MAX_N];
vis=new boolean [MAX_N];
e=new edge [MAX_N];
for(int i=0;i<MAX_N;i++) e[i]=new edge();
}
static class edge{
int v,w,next;
}
}