zoukankan      html  css  js  c++  java
  • 852. spfa判断负环

    给定一个n个点m条边的有向图,图中可能存在重边和自环, 边权可能为负数。

    请你判断图中是否存在负权回路。

    输入格式

    第一行包含整数n和m。

    接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。

    输出格式

    如果图中存在负权回路,则输出“Yes”,否则输出“No”。

    数据范围

    1n2000
    1m10000
    图中涉及边长绝对值均不超过10000。

    输入样例:

    3 3
    1 2 -1
    2 3 4
    3 1 -4
    

    输出样例:

    Yes

    代码:
    //邻接表存储
    //n=1e5,不能用邻接表
    
    import java.util.ArrayDeque;
    import java.util.Arrays;
    import java.util.Scanner;
    
    public class Main{
            static final int N=100005, INF=0x3f3f3f3f;
            static int h[]=new int[N];
            static int e[]=new int[N];
            static int ne[]=new int[N];
            static int w[]=new int[N];
            static int dis[]=new int[N];
            static int cnt[]=new int[N];//
            static boolean vis[]=new boolean[N];
            static int n,m,idx;
            static void add(int a,int b,int c){
                    e[idx]=b;
                    w[idx]=c;
                    ne[idx]=h[a];
                    h[a]=idx++;
            }
            static boolean spfa(){
                    ArrayDeque<Integer> q = new ArrayDeque<Integer>();
                    Arrays.fill(dis, INF);
                    dis[1]=0;
                    for(int i=1;i<=n;i++){//不能只加入1了,因为每个点都要判断一下,负权回路并不是每个点都能进入的
                        q.offer(i);
                        vis[i]=true;
                    }
                    while(!q.isEmpty()){
                            int t=q.poll();
                            vis[t]=false;//不在队列中,置为false
                            for(int i=h[t];i!=-1;i=ne[i]){
                                    int j=e[i];
                                    if(dis[j]>dis[t]+w[i]){
                                            dis[j]=dis[t]+w[i];
                                            cnt[j]=cnt[t]+1;
                                            if(cnt[j]>=n) return true;//如果存在负权回路,路径那么会一直执行更新,就是在这个负环中转圈;对图中的点,它最多经过n-1条边到达另一个点,所以大于等于n,肯定是存在负权回路
                                            if(!vis[j]){
                                                    vis[j]=true;
                                                    q.offer(j);
                                            }
                                    }
                            }
                    }
                    return false;
            }
            public static void main(String[] args) {
                    Scanner scan=new Scanner(System.in);
                    n=scan.nextInt();
                    m=scan.nextInt();
                    Arrays.fill(h, -1);
                    while(m-->0){
                            int a=scan.nextInt();
                            int b=scan.nextInt();
                            int c=scan.nextInt();
                            add(a,b,c);
                    }
                    if(spfa()) System.out.println("Yes");
                    else System.out.println("No");
            }
    }
  • 相关阅读:
    时序图和类图
    word文档一个表格分割成两个表格
    Spring 报错:Error creating bean with name
    怎么让线条快速选中并组合多个形状
    [扩展阅读] Python 函数修饰符(装饰器)的使用
    第039 类和对象 拾遗
    吴恩达深度学习 第一课第三周课后编程作业
    第038讲:类和对象:继承 课后测试题及答案
    廖雪峰Python教程--使用模块
    第037讲:类和对象:面向对象编程
  • 原文地址:https://www.cnblogs.com/qdu-lkc/p/12255512.html
Copyright © 2011-2022 走看看