![在这里插入图片描述](https://img-blog.csdnimg.cn/20210501003220381.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3M3enJf,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210501003416340.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3M3enJf,size_16,color_FFFFFF,t_70)
路径压缩:使每个点都直接指向根节点,修改find方法
1376. 通知所有员工所需的时间
- 保存结果
- 由当前结点向上遍历,寻找最值
private int[] min;
public int numOfMinutes(int n, int headID, int[] manager, int[] informTime) {
min = new int[n];
Arrays.fill(min, Integer.MAX_VALUE);
min[headID] = 0;
int result = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
result = Math.max(result, countMin(i, manager, informTime));
}
return result;
}
private int countMin(int n, int[] manager, int[] informTime) {
if (min[n] != Integer.MAX_VALUE) {
return min[n];
}
min[n] = informTime[manager[n]]+countMin(manager[n], manager, informTime);
return min[n];
}
1631. 最小体力消耗路径
法二:
并查集法:
- 二维数组转化成一维数组表示***二维数组应用并查集
- 将各个边赋权,并排序
- 从小到大逐次加边,看起始点和终点是否联通(最小生成树)
class Solution{
public int minimumEffortPath(int[][] heights) {
int m = heights.length;
int n = heights[0].length;
List<int[]> edges = new ArrayList<int[]>();
for(int i=0;i<m;i++) {
for(int j=0;j<n;j++) {
//二维数组,一维表示
int id = i*n +j;
//在这里构造无向图,所以只看两个方向就够了
if(i>0) {
edges.add(new int[] {id-n,id,Math.abs(heights[i-1][j]-heights[i][j])});
}
if(j>0) {
inf[i][j] = Math.abs(heights[i][j-1]-heights[i][j]);
edges.add(new int[] {id-1,id,Math.abs(heights[i][j-1]-heights[i][j])});
}
}
}
//排序**
Collections.sort(edges,new Comparator<int []>() {
@Override
public int compare(int[] o1, int[] o2) {
// TODO Auto-generated method stub
return o1[2]-o2[2];
}
});
UnionFind uf = new UnionFind(m*n);
int ans = 0;
//从小到大加边,看是否连通
for(int[] edge : edges) {
int x = edge[0],y = edge[1],v = edge[2];
uf.union(x, y);
if(uf.isconnected(0, m*n-1)) {
ans =v;
break;
}
}
return ans;
}
}
//并查集模板
class UnionFind{
int[] parent;
//联通数量
int count;
public UnionFind(int n) {
parent = new int[n];
for(int i=0;i<n;i++) {
parent[i] = i;
}
count = n;
}
public int find(int x) {
return (int) (x==parent[x]?x:(parent[x]==find(parent[x])));
}
public void union(int x,int y) {
int rootx = find(x);
int rooty = find(y);
if(rootx==rooty)return;
parent[rootx] = rooty;
count--;
}
public boolean isconnected(int x,int y) {
return find(x)==find(y);
}
}
国王的烦恼
法一:当结点的度数为0时,点孤立,居民开始抱怨(30分)
package lanqiao;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Scanner;
class node{
int start;
int end;
int day;
public node(int start,int end,int day) {
this.start = start;
this.end = end;
this.day =day;
}
}
public class PREV_22 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int count=0;
int n = sc.nextInt();
int m = sc.nextInt();
//结点度数表
int[] degree = new int[n+1];
ArrayList<node> arr = new ArrayList();
for(int i=0;i<m;i++) {
int s = sc.nextInt();
int e = sc.nextInt();
int d = sc.nextInt();
arr.add(new node(s,e,d));
degree[s]++;
degree[e]++;
}
//比较器排序
arr.sort(new Comparator<node>() {
@Override
public int compare(node o1, node o2) {
// TODO Auto-generated method stub
return o1.day-o2.day;
}
});
//n条边,循环n次,每次找最小边
int left = 0;
int right = 0;
while(right<m) {
if(right==m-1||arr.get(right).day<arr.get(right+1).day){
int flag = 0;
for(int i=left;i<=right;i++) {
--degree[arr.get(i).start];
--degree[arr.get(i).end];
if(degree[arr.get(i).start]==0||degree[arr.get(i).end]==0) {
flag = 1;
}
}
if(flag==1) count++;
left = right+1;
}
right++;
}
System.out.println(count);
}
}
法二:并查集思想,反向构建构建树,如果不连通则抱怨
联系01背包,反向遍历
从天数较大的边反向构建时候不会受到天数较小边的影响***(超时,90分)
package lanqiao;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Scanner;
public class PRVE_22并查集 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int count=0;
int day=0;
int n = sc.nextInt();
int m = sc.nextInt();
unionFind u = new unionFind(n+1);
ArrayList<node1> arr = new ArrayList();
for(int i=0;i<m;i++) {
int s = sc.nextInt();
int e = sc.nextInt();
int d = sc.nextInt();
arr.add(new node1(s,e,d));
}
arr.sort(new Comparator<node1>() {
@Override
public int compare(node1 o1, node1 o2) {
// TODO Auto-generated method stub
return o2.day-o1.day;
}
});
for(int i=0;i<m;i++) {
node1 temp = arr.get(i);
if(!u.isconnected(temp.start, temp.end)) {
if(day!=temp.day)
count++;
u.union(temp.start, temp.end);
day = temp.day;
}
}
System.out.println(count);
}
}
class unionFind{
int[] parent;
//连通分量
public unionFind(int num){
parent = new int[num];
//初始化
for(int i=0;i<num;i++) {
parent[i] = i;
}
}
public int find(int x) {
while(parent[x]!=x) {
x = parent[x];
}
return x;
}
public void union(int x,int y) {
int xp = find(x);
int yp = find(y);
if(xp == yp)return;
parent[xp] = yp;
return;
}
public boolean isconnected(int x,int y) {
return find(x)==find(y);
}
}
class node1{
int start;
int end;
int day;
public node1(int start,int end,int day) {
this.start = start;
this.end = end;
this.day =day;
}
}