用队列来维护搜索的顺序,一层一层往下搜,相当于BFS
。
每次用当前搜的这一轮的最短距离去更新下一轮的最短距离。
初始化dist
数组为INF
,这样做的目的是便于去判断是否走到n
存在最短路。
st[]
数组存的是当前在队列中的元素,所以在每次入队时,可以将元素置为true,表示在队列中。
出队时,再将元素置为false,表示不在队列中,这样就避免了更新重复元素的最短路。
import java.util.*;
public class Main{
static int N=100010,n,m,idx,INF=0x3f3f3f3f;
static int []h=new int[N],e=new int[N],ne=new int[N],w=new int[N];
static int []q=new int[N];
static int []dist=new int[N];
static boolean []st=new boolean[N];
public static void add(int a,int b,int c){
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
public static void spfa(){
Queue<Integer>q=new LinkedList<>();
Arrays.fill(dist,INF);
q.offer(1);
dist[1]=0;
st[1]=true;
while(!q.isEmpty()) {
int t=q.poll();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]) {
int j=e[i];
if(dist[j]>dist[t]+w[i]) {
dist[j]=dist[t]+w[i];
//满足这个条件的才需要入队
//写在外面就会将不满足这个条件的都入队
if(!st[j]) {
q.offer(j);
st[j]=true;
}
}
}
}
if(dist[n]==INF)System.out.println("impossible");
else System.out.println(dist[n]);
}
public static void main(String []args){
Scanner in = new Scanner(System.in);
n=in.nextInt();
m=in.nextInt();
Arrays.fill(h, -1);
while(m-->0) {
int a=in.nextInt();
int b=in.nextInt();
int c=in.nextInt();
add(a, b, c);
}
spfa();
}
}
用队列来维护搜索的顺序,一层一层往下搜,相当于BFS
。
每次用当前搜的这一轮的最短距离去更新下一轮的最短距离。
cnt[j]=cnt[t]+1;
记录走到当前这个点所经过(用到)的边数
if(cnt[j]>=n)return true;
解释:走了n
个点对应的是n-1
条边,如果说边数大于等于n
则说明是至少是n+1
个点。
但是我们最多只有n
个点,说明必定有部分点重复,形成回路。
由于比较的是最短距离,所以该回路必定是负权回路。
st[]
数组存的是当前在队列中的元素,所以在每次入队时,可以将元素置为true
,表示在队列中。 出队时,再将元素置为false
,表示不在队列中,这样就避免了更新重复元素的最短路。
//spfa()判断负环
import java.util.*;
public class Main{
static int N=2010,M=10010,n,m,idx;
static int e[]=new int [M];
static int ne[]=new int[M];
static int h[]=new int [N];
static int w[]=new int[M];
static int dist[]=new int [N];
static int cnt[]=new int[N];
static boolean st[]=new boolean[N];
//存的是否在当前的队列中
public static void add(int a,int b ,int c){
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
public static boolean spfa(){
Queue<Integer>q=new LinkedList<>();
//用队列来维护搜索的顺序,一层一层往下搜,相当于BFS。
//每次用当前搜的这一轮的最短距离去更新下一轮的最短距离。
for(int i=1;i<=n;i++){
q.offer(i);
st[i]=true;
}
//由于求的是图中的负环不是从1号点到n号点的负环
//所以每个点都需要入队,并置为true。
while(!q.isEmpty()){
int t=q.poll();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>dist[t]+w[i]){
dist[j]=dist[t]+w[i];
cnt[j]=cnt[t]+1;
//记录走到当前这个点所用的边数
if(cnt[j]>=n)return true;
//走了n个点对应的是n-1条边
//如果说边数大于等于n则说明是至少是n+1个点
//但是我们最多只有n个点,说明必定有些点重复,形成回路。
//但是由于比较的是最短距离,所以该回路必定是负权回路。
//满足这个条件的才需要入队
//写在外面就会将不满足这个条件的都入队
if(!st[j]){
q.offer(j);
st[j]=true;
}
}
}
}
return false;
}
public static void main(String []args){
Scanner in = new Scanner(System.in);
n=in.nextInt();
m=in.nextInt();
Arrays.fill(h,-1);
//初始化h[]数组为空
while(m-->0){
int a=in.nextInt();
int b=in.nextInt();
int c=in.nextInt();
add(a,b,c);
}
if(spfa())System.out.println("Yes");
else System.out.println("No");
}
}
import java.util.*;
public class Main{
static int N=2010,M=10010,n,m,idx;
static int e[]=new int [M];
static int ne[]=new int[M];
static int h[]=new int [M];
static int w[]=new int[M];
static int dist[]=new int [N];
static int cnt[]=new int[N];
static boolean st[]=new boolean[N];
public static void add(int a,int b ,int c){
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
public static boolean spfa(){
Queue<Integer>q=new LinkedList<>();
for(int i=1;i<=n;i++){
q.offer(i);
st[i]=true;
}
while(!q.isEmpty()){
int t=q.poll();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>dist[t]+w[i]){
dist[j]=dist[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n)return true;
if(!st[j]){
q.offer(j);
st[j]=true;
}
}
}
}
return false;
}
public static void main(String []args){
Scanner in = new Scanner(System.in);
n=in.nextInt();
m=in.nextInt();
Arrays.fill(h,-1);
while(m-->0){
int a=in.nextInt();
int b=in.nextInt();
int c=in.nextInt();
add(a,b,c);
}
if(spfa())System.out.println("Yes");
else System.out.println("No");
}
}