算法筆記_075:藍橋杯練習 最短路(Java)


目錄

1 問題描述

2 解決方案

2.1 floyd算法解決

2.2 spfa算法解決

 


1 問題描述

問題描述

給定一個n個頂點,m條邊的有向圖(其中某些邊權可能為負,但保證沒有負環)。請你計算從1號點到其他點的最短路(頂點從1到n編號)。

輸入格式

第一行兩個整數n, m。

接下來的m行,每行有三個整數u, v, l,表示u到v有一條長度為l的邊。

輸出格式
共n-1行,第i行表示1號點到i+1號點的最短路。
樣例輸入
3 3
1 2 -1
2 3 -1
3 1 2
樣例輸出
-1
-2
數據規模與約定

對於10%的數據,n = 2,m = 2。

對於30%的數據,n <= 5,m <= 10。

對於100%的數據,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保證從任意頂點都能到達其他所有頂點。

 


2 解決方案

2.1 floyd算法解決

使用floyd算法(ps:算法筆記_069:Floyd算法簡單介紹(Java))求解本題的時間復雜度為O(n^3),下面代碼在系統中測評分為40,原因:運行超時。以下代碼僅供參考。

具體代碼如下:

import java.util.Scanner;

public class Main {
    
    public void floyd(long[][] adjMatrix) {
        for(int k = 0;k < adjMatrix.length;k++) {
            for(int i = 0;i < adjMatrix.length;i++) {
                for(int j  = 0;j < adjMatrix.length;j++) {
                    if(adjMatrix[i][k] != Integer.MAX_VALUE && adjMatrix[k][j] != Integer.MAX_VALUE) {
                        if(adjMatrix[i][j] > adjMatrix[i][k] + adjMatrix[k][j])
                            adjMatrix[i][j] = adjMatrix[i][k] + adjMatrix[k][j];
                    }
                }
            }
         }
        for(int i = 1;i < adjMatrix.length;i++)
            System.out.println(adjMatrix[0][i]);
    }
    
    public static void main(String[] args) {
        Main test = new Main();
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        if(n > 20000 || n < 1 || m > 200000 || m < 1)
            return;
        long[][] adjMatrix = new long[n][n];
        for(int i = 0;i < n;i++) {
            for(int j = 0;j < n;j++)
                adjMatrix[i][j] = Integer.MAX_VALUE;
        }
        for(int i = 0;i < m;i++) {
            int a = in.nextInt();
            int b = in.nextInt();
            int value = in.nextInt();
            if(value > 10000 || value < -10000)
                return;
            adjMatrix[a - 1][b - 1] = value;
        }
        test.floyd(adjMatrix);
    }
    
}

 

 

2.2 spfa算法解決

使用spfa算法(PS:算法筆記_071:SPFA算法簡單介紹(Java))求解本題的時間復雜度為O(m*E)(PS:其中E為給定邊的數目,m為圖中頂點進出鏈表的總次數,一般不大於2*nn為圖中總頂點數)。下面的給出的代碼,在系統中測評分為70或者80分(PS:同樣代碼提交了兩次,評分不一樣),具體原因:運行超時。可能是Java語言編譯時間沒有C/C++那么快,所以不能在1s內完成。如果是樓主自己代碼問題,還請路過同學不吝賜教啊~

 

 

 

 

具體代碼如下: 

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
    
    static class edge {
        public int a;  //邊的起點
        public int b;  //邊的終點
        public int value;  //邊的權值
        
        edge(int a, int b, int value) {
            this.a = a;
            this.b = b;
            this.value = value;
        }
    }
    
    public void spfa(ArrayList<edge>[] listA, int n) {
        long[] result = new long[n];
        int[] num = new int[n];
        boolean[] used = new boolean[n];
        for(int i = 1;i < n;i++) {
            result[i] = Integer.MAX_VALUE;
            used[i] = false;
        }
        LinkedList<Integer> list = new LinkedList<Integer>();
        list.add(0);
        num[0] = 1;
        used[0] = true;
        while(list.size() > 0) {
            int start = list.getFirst();
            for(int i = 0, length = listA[start].size();i < length;i++) {
                int b = listA[start].get(i).b;
                int value = listA[start].get(i).value;
                if(result[b - 1] > result[start] + value) {
                    result[b - 1] = result[start] + value;
                    if(!used[b - 1]) {
                        used[b - 1] = true;
                        list.add(b - 1);
                        num[b - 1]++;
                        if(num[b - 1] > n)
                            return;
                    }
                }
            }
            list.removeFirst();
            used[start] = false;    
        }
        for(int i = 1;i < n;i++)
            System.out.println(result[i]);
        return;
    }
    
    public static void main(String[] args) {
        Main test = new Main();
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        if(n > 20000 || n < 1 || m > 200000 || m < 1)
            return;
        @SuppressWarnings("unchecked")
        ArrayList<edge>[] listA = new ArrayList[n];
        for(int i = 0;i < n;i++)
            listA[i] = new ArrayList<edge>();
        for(int i = 0;i < m;i++) {
            int a = in.nextInt();
            int b = in.nextInt();
            int value = in.nextInt();
            if(value > 10000 || value < -10000)
                return;
            listA[a - 1].add(new edge(a, b, value));
        }
        test.spfa(listA, n);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM