1129. 熱浪 - AcWing題庫
這道題可以有三種方法來做,樸素版的dijkstra、堆優化版的dijkstra和spfa算法
(1)spfa算法?
?這里的隊列用循環隊列,而不是像模板那樣用普通隊列是因為它的隊列長度不確定
import java.util.*;public class Main{static int N = 2510, M = 2 * 6200 + 10;static int n, m, S, T, idx;static int[] dist = new int[N];static int[] q = new int[N];static int[] h = new int[N], ne = new int[M], e = new int[M], w = new int[M];//鄰接表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(){Arrays.fill(dist, 0x3f3f3f3f);dist[S] = 0;int hh = 0, tt = 1;//循環隊列q[0] = S;st[S] = true;//在隊列里面while(hh != tt){//循環隊列判斷為空的條件int t = q[hh ++];if(hh == N) hh = 0;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[tt ++] = j;//加入循環隊列if(tt == N) tt = 0;st[j] = true;}}}}}public static void main(String[] args){Scanner sc = new Scanner(System.in);n = sc.nextInt();//點m = sc.nextInt();//邊S = sc.nextInt();//起點T = sc.nextInt();//終點//建圖Arrays.fill(h, -1);//這個一定要記得for(int i = 0; i < m; i ++){int a = sc.nextInt();int b = sc.nextInt();int c = sc.nextInt();add(a, b, c);//無向圖add(b, a, c);}spfa();System.out.print(dist[T]);}
}
(2) dijkstra堆優化算法
import java.util.*;class PII implements Comparable<PII>{int distance, num;public PII(int distance, int num){this.distance = distance;this.num = num;}public int compareTo(PII o){return distance - o.distance;}
}public class Main{static int N = 2510, M = 2 * 6200 + 10;static int n, m, S, T, idx;static int[] dist = new int[N];static int[] h = new int[N], ne = new int[M], e = new int[M], w = new int[M];//鄰接表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 dijkstra(){PriorityQueue<PII> q = new PriorityQueue<>();//優先隊列Arrays.fill(dist, 0x3f3f3f3f);dist[S] = 0;q.offer(new PII(0, S));while(!q.isEmpty()){PII t = q.poll();int distance = t.distance;//到起點的距離int num = t.num;//點的編號if(st[num]) continue;//遍歷過了st[num] = true;//標記為遍歷過for(int i = h[num]; i != -1; i = ne[i]){int j = e[i];if(dist[j] > distance + w[i]){dist[j] = distance + w[i];if(!st[j]) q.offer(new PII(dist[j], j));}}}}public static void main(String[] args){Scanner sc = new Scanner(System.in);n = sc.nextInt();//點m = sc.nextInt();//邊S = sc.nextInt();//起點T = sc.nextInt();//終點//建圖Arrays.fill(h, -1);//這個一定要記得for(int i = 0; i < m; i ++){int a = sc.nextInt();int b = sc.nextInt();int c = sc.nextInt();add(a, b, c);//無向圖add(b, a, c);}dijkstra();System.out.print(dist[T]);}
}
1128. 信使 - AcWing題庫
????????這道題是讓我們求出指揮部到所有點的最短距離,取一個最大值,如果存在一個點距離指揮部的距離是正無窮的話,就輸出-1。?
? ? ? ? 這道題雖然是讓我們求單源最短路,但是我們也可以用多源最短路的Floyd算法來求。
Floyd算法?
import java.util.*;public class Main{static int N = 110;static int[][] dist = new int[N][N];static int n, m;public static void main(String[] args){Scanner sc = new Scanner(System.in);n = sc.nextInt();m = sc.nextInt();for(int i = 1; i <= n; i ++){for(int j = 1; j <= n; j ++){if(i == j) dist[i][j] = 0;else dist[i][j] = 0x3f3f3f3f;}}for(int i = 1; i <= m; i ++){int a = sc.nextInt();int b = sc.nextInt();int c = sc.nextInt();dist[a][b] = dist[b][a] = Math.min(dist[a][b], c);//防止出現重邊}//開始Floy算法for(int k = 1; k <= n; k ++){for(int i = 1; i <= n; i ++){for(int j = 1; j <= n; j ++){dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);}}}//找到最大的那條最短路徑int res = 0;for(int i = 1; i <= n; i ++){if(dist[1][i] == 0x3f3f3f3f){res = -1;break;}res = Math.max(res, dist[1][i]);}//輸出最大值System.out.print(res);}
}
?
?1127. 香甜的黃油 - AcWing題庫
????????這道題是本質上是一個多源最短路問題,讓我們算出每個點到其他點的距離之和的最小值,但是這道題的數據很大,如果用Floyd算法會超時,所以這里我們可以用spfa算法算出n個點的情況,去一個最小值。
spfa算法?
import java.util.*;public class Main{static int N = 810, M = 3000, INF = 0x3f3f3f3f;static int n, m, p, idx;static int[] id = new int[N];//奶牛所在牧場編號static int[] q = new int[N];//循環隊列static int[] h = new int[N], e = new int[M], ne = new int[M], w = new int[M];static boolean[] st = new boolean[N];static int[] dist = new int[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 int spfa(int u){Arrays.fill(dist, INF);dist[u] = 0;int hh = 0, tt = 1;q[0] = u;st[u] = true;while(hh != tt){int t = q[hh ++];if(hh == N) hh = 0;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[tt ++] = j;if(tt == N) tt = 0;st[j] = true;}}}}int res = 0;for(int i = 0; i < n; i ++){int j = id[i];//奶牛所在牧場編號if(dist[j] == INF){return INF;} res += dist[j];}return res;}public static void main(String[] args){Scanner sc = new Scanner(System.in);n = sc.nextInt();p = sc.nextInt();m = sc.nextInt();Arrays.fill(h, -1);for(int i = 0; i < n; i ++){id[i] = sc.nextInt();}for(int i = 1; i <= m; i ++){int a = sc.nextInt();int b = sc.nextInt();int c = sc.nextInt();add(a, b, c);//無向圖add(b, a, c);}int res = INF;for(int i = 1; i <= p; i ++){//所有奶牛到第i個牧場的距離之和res = Math.min(res, spfa(i));}System.out.print(res);}
}
?
?1126. 最小花費 - AcWing題庫
這道題要我們求a的最少錢數,因為有100=da*w1*w2*...(其中這里的w是指1-手續費%,也就是匯率),要先da最小,那么就是說要w的乘積最大?
樸素版dijkstra算法?
import java.util.*;public class Main{static int N = 2010;static int n, m, start, end;static double[][] g = new double[N][N];//鄰接矩陣存儲邊static double[] dist = new double[N];//起點到其他點的距離static boolean[] st = new boolean[N];public static void dijkstra(){//Arrays.fill(dist, 0x3f3f3f3f);我們要求的是dist的最大值,所以這里不需要這句話dist[start] = 1;for(int i = 1; i <= n; i ++){//遍歷n次,每次找到一個int t = -1;for(int j = 1; j <= n; j ++){if(!st[j] && (t == -1 || dist[j] > dist[t])){t = j;}}st[t] = true;//標記為遍歷過for(int j = 1; j <= n; j ++){dist[j] = Math.max(dist[j], dist[t] * g[t][j]);}}}public static void main(String[] args){Scanner sc = new Scanner(System.in);n = sc.nextInt();m = sc.nextInt();for(int i = 0; i < m; i ++){int a = sc.nextInt();int b = sc.nextInt();int c = sc.nextInt();double z = (100.0 - c) / 100.0;//這里為什么取最大值?因為原本是要求c最小的,而現在的z與c的關系是相反的,所以取最大g[a][b] = g[b][a] = Math.max(g[a][b], z);//防止重邊}start = sc.nextInt();end = sc.nextInt();dijkstra();//我們求的dist是w乘積的最大值,如果想要da的最大值,就要用100來除distSystem.out.printf("%.8f", 100.0 / dist[end]);}
}
?
920. 最優乘車 - AcWing題庫
換車的最小次數=坐車的最小次數 - 1?
由于這道題所有邊的權重是1,所以可以直接用bfs,不需要用dijkstra、spfa什么的
import java.util.*;
import java.io.*;public class Main{static int N = 510;static int n, m, res, INF = 0x3f3f3f3f;static int[] q = new int[N];//用數組來模擬隊列static boolean[][] g = new boolean[N][N];//true表示連通,false表示不連通static int[] dist = new int[N];//最小坐車次數static int[] cnt = new int[N];//每條線路經過的巴士站public static void bfs(){Arrays.fill(dist, INF);dist[1] = 0;int hh = 0, tt = -1;q[++ tt] = 1;while(hh <= tt){int t = q[hh ++];//取出隊頭for(int i = 1; i <= n; i ++){if(g[t][i] && dist[i] > dist[t] + 1){dist[i] = dist[t] + 1;q[++ tt] = i;}}}}public static void main(String[] args)throws IOException{BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String[] s = br.readLine().split(" ");m = Integer.parseInt(s[0]);n = Integer.parseInt(s[1]);for(int i = 0; i < m; i ++){String[] arr = br.readLine().split(" ");int len = arr.length;//這條線路經過多少個車站for(int j = 0; j < len; j ++) cnt[j] = Integer.parseInt(arr[j]);for(int j = 0; j < len; j ++){//這個車站和它后面的車站之間都連通(單程)for(int k = j + 1; k < len; k ++){g[cnt[j]][cnt[k]] = true;//連通置為true}}}bfs();if(dist[n] == INF) System.out.print("NO");else System.out.print(dist[n] - 1);}
}
?
903. 昂貴的聘禮 - AcWing題庫
用一個虛擬遠點將這些點聯系起來,建圖?
?
?
import java.util.*;public class Main{static int N = 110;static int n, m;static int[][] g = new int[N][N];//用于建圖static int[] dist = new int[N];static boolean[] st = new boolean[N];static int[] level = new int[N];//每個點的等級public static int dijkstra(int down, int up){//因為要枚舉多個區間,所以每次開始之前都要進行初始化Arrays.fill(st, false);Arrays.fill(dist, 0x3f3f3f3f);dist[0] = 0;//虛擬遠點的距離置為0//樸素版的dijkstra,因為建立了一個虛擬遠點,所以循環的時候要從0開始for(int i = 0; i <= n; i ++){int t = -1;for(int j = 0; j <= n; j ++){if(!st[j] && (t == -1 || dist[t] > dist[j])){t = j;}}st[t] = true;//更新其他點的值for(int j = 0; j <= n; j ++){if(level[j] >= down && level[j] <= up){dist[j] = Math.min(dist[j], dist[t] + g[t][j]);}}}return dist[1];}public static void main(String[] args){Scanner sc = new Scanner(System.in);m = sc.nextInt();n = sc.nextInt();//初始化for(int i = 0; i < N; i ++){Arrays.fill(g[i], 0x3f3f3f3f);}for(int i = 0; i < N; i ++){g[i][i] = 0;}//建圖for(int i = 1; i <= n; i ++){int price = sc.nextInt();level[i] = sc.nextInt();int cnt = sc.nextInt();//有幾種兌換方式g[0][i] = price;//虛擬遠點到當前點的距離(不兌換,直接購買)for(int j = 1; j <= cnt; j ++){int id = sc.nextInt();int cost = sc.nextInt();g[id][i] = cost;//兌換物品到當前點的距離}}int res = 0x3f3f3f3f;//枚舉等級的左端點,找到最小的等級,因為我們一定要將第一個點包含在內for(int i = level[1] - m; i <= level[1]; i ++) res = Math.min(res, dijkstra(i, i + m));System.out.print(res);}
}
?