题目链接:
https://www.luogu.com.cn/problem/P1967
是一道最小生成树+LCA的模板组合题目.
代码比较长....
计算最多能运送多少重量的货物,首先会想到计算最大生成树.这样就能够保证联通所有路的情况下,道路载重最大.
因为最终计算的是某两点之间的最大载重量,所以我们需要计算两点之间的路径上最小的载重是多少.
在倍增法LCA中,我们通过动态规划可以计算出每个节点的跳跃路径,我们也可以使用同样的方式记录在跳跃过程中,道路的最小载重.
for (int j = 1; j <= maxLevel; j++) { for (int i = 1; i <= n; i++) { parentInfo[i][j] = parentInfo[parentInfo[i][j - 1]][j - 1]; parentMinWeightInfo[i][j] = Math.min(parentMinWeightInfo[i][j-1],parentMinWeightInfo[parentInfo[i][j - 1]][j - 1]); } }
最终,在进行询问的时候,可以进行比较,得出最终结果.
因为给出的点之间可能并不联通,是一个森林,所以在询问之前,需要进行联通判断.不在一个并查集中,就输出-1.
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.*; public class Main { static int[] p, level; static PriorityQueue<int[]> pq; static LinkedList<int[]>[] adj; static boolean[] isVisit; static int[][] parentInfo,parentMinWeightInfo; static int maxLevel,n,m; public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); n = Integer.parseInt(st.nextToken()); m = Integer.parseInt(st.nextToken()); p = new int[n + 1]; pq = new PriorityQueue<>(new Comparator<int[]>() { @Override public int compare(int[] o1, int[] o2) { return o2[2] - o1[2]; } }); for (int i = 1; i <= n; i++) { p[i] = i; } int from, to, weight; for (int i = 1; i <= m; i++) { st = new StringTokenizer(br.readLine()); from = Integer.parseInt(st.nextToken()); to = Integer.parseInt(st.nextToken()); weight = Integer.parseInt(st.nextToken()); pq.add(new int[]{from, to, weight}); } adj = new LinkedList[n + 1]; for (int i = 0; i < adj.length; i++) { adj[i] = new LinkedList<int[]>(); } int[] edge; while (!pq.isEmpty()) { edge = pq.poll(); from = edge[0]; to = edge[1]; weight = edge[2]; if (!connect(from, to)) { union(from, to); adj[from].add(new int[]{to, weight}); adj[to].add(new int[]{from, weight}); } } isVisit = new boolean[n + 1]; level = new int[n + 1]; for (int i = 1; i <= n; i++) { if (!isVisit[i]) { dfs(i,0); } } maxLevel = 0; for (int i = 1; i <= n; i++) { maxLevel = Math.max(maxLevel, level[i]); } int temp = 0; while ((1 << temp) < maxLevel) { temp++; } maxLevel = temp; parentInfo = new int[n + 1][maxLevel + 1]; parentMinWeightInfo = new int[n + 1][maxLevel + 1]; isVisit = new boolean[n + 1]; for (int i = 1; i <= n; i++) { if (!isVisit[i]) { parentMinWeightInfo[i][0] = Integer.MAX_VALUE; dfs2(i); } } for (int j = 1; j <= maxLevel; j++) { for (int i = 1; i <= n; i++) { parentInfo[i][j] = parentInfo[parentInfo[i][j - 1]][j - 1]; parentMinWeightInfo[i][j] = Math.min(parentMinWeightInfo[i][j-1],parentMinWeightInfo[parentInfo[i][j - 1]][j - 1]); } } st = new StringTokenizer(br.readLine()); StringBuilder bu = new StringBuilder(); int q = Integer.parseInt(st.nextToken()); int a, b; for (int i = 0; i < q; i++) { st = new StringTokenizer(br.readLine()); a = Integer.parseInt(st.nextToken()); b = Integer.parseInt(st.nextToken()); if(!connect(a,b)){ bu.append(-1) ; if(i != q-1){ bu.append("\n"); } continue; } int ans = LCA(a,b); bu.append(ans) ; if(i != q-1){ bu.append("\n"); } } System.out.println(bu.toString()); } private static void dfs(int from,int deep) { isVisit[from] = true; level[from] = ++deep; for (int[] next : adj[from]) { if (!isVisit[next[0]]) { dfs(next[0],deep); } } } private static void dfs2(int from){ isVisit[from] = true; for (int[] next : adj[from]) { if (!isVisit[next[0]]) { parentMinWeightInfo[next[0]][0] = next[1]; parentInfo[next[0]][0] = from; dfs2(next[0]); } } } private static int LCA(int a, int b){ if(level[a]<level[b]){ int temp =a; a = b; b = temp; } int ans = Integer.MAX_VALUE; for(int i = maxLevel;i>=0;i--){ if(level[parentInfo[a][i]]>=level[b]){ ans = Math.min(ans, parentMinWeightInfo[a][i]); a = parentInfo[a][i]; } } if(a == b){ return ans; } for(int i = maxLevel;i>=0;i--){ if(parentInfo[a][i]!=parentInfo[b][i]){ ans = Math.min(ans,Math.min(parentMinWeightInfo[a][i],parentMinWeightInfo[b][i])); a = parentInfo[a][i]; b = parentInfo[b][i]; } } ans = Math.min(ans,Math.min(parentMinWeightInfo[a][0],parentMinWeightInfo[b][0])); return ans; } private static int find(int a) { if (p[a] == a) { return p[a]; } return p[a] = find(p[a]); } private static void union(int a, int b) { int A = find(a); int B = find(b); p[A] = B; } private static boolean connect(int a, int b) { return find(a) == find(b); } }