Problem C 城市道路
題目描述
n個城市之間有若干道路,其中某些道路黑夜需要關閉,分別求出城市1到城市n白天和黑夜的最短路徑。
輸入格式
第一行爲數據組數T
對於每組測試數據
第一行三個整數,n,m,k. (1<=n<=50)n表示城市個數,m表示道路個數,k表示黑夜需要關閉的道路個數。
接下來m行,每行 三個整數 a,b,c (1<=a,b<=n),其中第 i 行(1<=i <=m)表示第 i 條道路爲從城市a到城市b長度爲c(可能存在重複邊)。
接下來k行,每行一個整數w,表示黑夜要關閉的道路編號。
輸出格式
每組數據輸出兩行
第一行爲白天從城市1到城市n的最短距離
第一行爲黑夜從城市1到城市n的最短距離
輸入樣例
1
4 4 1
1 2 1
2 3 1
3 4 1
1 4 1
4
輸出樣例
1
3
解答:(Dijkstra算法)
import java.util.Arrays;
import java.util.Scanner;
/*
Problem C 最短路徑
題目
計算從城市1到城市n的最短路徑長度。分爲白天和黑夜,黑夜會關掉若干條線路,分別計算城市1到城市n的在白天和黑夜的最短路徑長度。保證每個城市與其他城市必有連接。兩個城市之間可能有多重邊
輸入
第一行輸入T,測試用例組數
第二行輸入n,m,k. n是城市數,m是邊數,k是黑夜關閉的邊數(n<=50)
接下來m行,每行輸入三個數x,y,z,代表城市x和城市y之間的距離
最後一行k個數,代表晚上關閉的線路序號
輸出
每組數據輸出兩行,分別代表白天和黑夜,城市1到n的最短路徑長度
測試用例
輸入
1
4 4 1
1 2 1
2 3 1
3 4 1
1 4 1
4
輸出
1
3
*/
public class Test{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()) {
int number = scanner.nextInt();
for(int i = 0; i < number; i++) {
int c = scanner.nextInt();
int v = scanner.nextInt();
int nv = scanner.nextInt();
int[] night = new int[nv];
int[][] num = new int[c][c];
int[][] graph = new int[v][3];
for(int j = 0; j < v; j++) {
graph[j][0] = scanner.nextInt() - 1;
graph[j][1] = scanner.nextInt() - 1;
graph[j][2] = scanner.nextInt();
}
for(int j = 0; j < nv; j++) night[j] = scanner.nextInt() - 1;
for(int j = 0; j < c; j++) num[graph[j][1]][graph[j][0]] = num[graph[j][0]][graph[j][1]] = graph[j][2]; //初始化圖 - 白天的圖
int value = Dijkstra(num, 1, c);
System.out.println(value);
//黑夜後
int l = 0;
num = new int[c][c];
for(int j = 0; j < c; j++) //初始化圖 - 黑夜時重新建圖(因爲有多重邊)
if(j == night[l]) {
l++;
continue;
}else num[graph[j][1]][graph[j][0]] = num[graph[j][0]][graph[j][1]] = graph[j][2];
for(int j = 0; j < c; j++)
value = Dijkstra(num, 1, c);
System.out.println(value);
}
}
}
public static int Dijkstra(int[][] nums, int s, int n) {//s起點,n爲終點
int[] d = new int[nums.length];//起點到各點的距離長度
boolean[] visit = new boolean[nums.length];//是否訪問過
Arrays.fill(d, Integer.MAX_VALUE);//填滿距離數組,都爲最大值
d[s - 1] = 0;//起點到起點距離爲0
for(int i = 0; i < nums.length; i++) {
int u = -1, min = Integer.MAX_VALUE;//d[u]最小,min中存放該最小的d[u]
for(int j = 0; j < nums.length; j ++) //起點到所有節點一趟中的最小值
if(visit[j] == false && d[j] < min) {
u = j;
min = d[j];
}
if(u == -1) return 0;//找不到小於min的d[u],說明剩下的頂點和起點s不連通
visit[u] = true;//賦值給起點到u
for(int v = 0; v < nums.length; v++)
if(visit[v] == false && nums[u][v] != 0 && d[u] + nums[u][v] < d[v]) //v未訪問 && u能到v && 以u爲中介可以使d[v]更優
d[v] = d[u] + nums[u][v];
}
return d[n - 1];
}
}
解答:(Floyd算法)
import java.util.Scanner;
/*
Problem C 最短路徑
題目
計算從城市1到城市n的最短路徑長度。分爲白天和黑夜,黑夜會關掉若干條線路,分別計算城市1到城市n的在白天和黑夜的最短路徑長度。保證每個城市與其他城市必有連接。兩個城市之間可能有多重邊
輸入
第一行輸入T,測試用例組數
第二行輸入n,m,k. n是城市數,m是邊數,k是黑夜關閉的邊數(n<=50)
接下來m行,每行輸入三個數x,y,z,代表城市x和城市y之間的距離
最後一行k個數,代表晚上關閉的線路序號
輸出
每組數據輸出兩行,分別代表白天和黑夜,城市1到n的最短路徑長度
測試用例
輸入
1
4 4 1
1 2 1
2 3 1
3 4 1
1 4 1
4
輸出
1
3
*/
public class Test{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()) {
int number = scanner.nextInt();
for(int i = 0; i < number; i++) {
int c = scanner.nextInt();
int v = scanner.nextInt();
int nv = scanner.nextInt();
int[] night = new int[nv];
int[][] num = new int[c][c];
int[][] graph = new int[v][3];
for(int j = 0; j < v; j++) {
graph[j][0] = scanner.nextInt() - 1;
graph[j][1] = scanner.nextInt() - 1;
graph[j][2] = scanner.nextInt();
}
for(int j = 0; j < nv; j++) night[j] = scanner.nextInt() - 1;
for(int j = 0; j < c; j++) { //初始化圖 - 白天的圖
for(int k = 0; k < c; k++)
if(j != k) num[j][k] = Integer.MAX_VALUE;
else num[j][k] = 0;
num[graph[j][1]][graph[j][0]] = num[graph[j][0]][graph[j][1]] = graph[j][2];
}
int value = Floyd(num, 1, c);
System.out.println(value);
//黑夜後
int l = 0;
for(int j = 0; j < c; j++) {//初始化圖 - 黑夜時重新建圖(因爲有多重邊)
for(int k = 0; k < c; k++)
if(j != k) num[j][k] = Integer.MAX_VALUE;
else num[j][k] = 0;
if(j == night[l]) {
l++;
continue;
}else num[graph[j][1]][graph[j][0]] = num[graph[j][0]][graph[j][1]] = graph[j][2];
}
for(int j = 0; j < c; j++)
value = Floyd(num, 1, c);
System.out.println(value);
}
}
}
public static int Floyd(int[][] nums, int s, int n) {
for(int k = 0; k < nums.length; k++)
for(int i = 0; i < nums.length; i++)
for(int j = 0; j < nums.length; j++)
if(nums[i][k] != Integer.MAX_VALUE && nums[k][j] != Integer.MAX_VALUE && nums[i][k] + nums[k][j] < nums[i][j])
nums[i][j] = nums[i][k] + nums[k][j];
return nums[s - 1][n - 1];
}
}