最小生成树1(Prim模板)、最小生成树2(kruskal模板)、最近公共祖先(模板)

最小生成树1(模板)

问题描述

给定一个包含 nn 个顶点和 mm 条边的无向图。图中可能存在重边和自环,且边的权值可能为负数。你需要求出最小生成树(MST)的边权重之和。如果无法构造最小生成树,则输出 "impossible"。

最小生成树:在一个无向图中,由 nn 个顶点和 n−1n−1 条边构成的连通子图,且该子图的边权重之和最小。

如果图不连通,无法形成最小生成树。

输入格式

第一行输入二个正整数 n,mn,m。

接下来 mm 行,每行输入 33 个正整数 a,b,ca,b,c。表示点 aa 到点 bb 存在一条无向边,权值为 cc。

2≤n≤500,1≤m≤105,1≤a,b≤n,1≤c≤1042≤n≤500,1≤m≤105,1≤a,b≤n,1≤c≤104。

输出格式

输出一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出 "impossible"。

样例输入

复制代码
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4

样例输出

复制代码
6
复制代码
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.*;


public class Main {

    static int N=2*100010;     
       
    static int n,m;
    static int id=1;
    
    static int dist[]=new int[N];
    static boolean isSure[]=new boolean[N];
   
    
    static int h[]=new int[N];
    static int e[]=new int[N];
    static int ne[]=new int[N];
    static int w[]=new int[N];
    
   
    
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
    static BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws IOException { 
    	
        StringTokenizer st=new StringTokenizer(br.readLine());
        n=Integer.parseInt(st.nextToken());  
        m=Integer.parseInt(st.nextToken());  
       
        
        for (int i = 0; i < m; i++) {
        	st=new StringTokenizer(br.readLine());
        	int a=Integer.parseInt(st.nextToken());
        	int b=Integer.parseInt(st.nextToken());
        	int c=Integer.parseInt(st.nextToken());
        	add(a,b,c);add(b,a,c);
		}
        
       
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[1]=0;
        
        
        PriorityQueue<Node> priorityQueue=new PriorityQueue<Node>();
        priorityQueue.add(new Node(1,0));
        int cnt=0;//一共选中几个点了
        int res=0;
        while(cnt<n && !priorityQueue.isEmpty()){
        	Node no=priorityQueue.poll();
        	int u=no.x;
        	if(!isSure[u]){
        		res+=dist[u];
    			isSure[u]=true;cnt++;
    			for (int i = h[u]; i > 0; i=ne[i]) {
					int son=e[i];
					if(!isSure[son]){
						if(dist[son]>w[i]){//这里表示的是到选中的集合的距离
							dist[son]=w[i];
							priorityQueue.add(new Node(son,dist[son]));
						}
					}
				}
        		
        		
        	}
        }
        if(cnt!=n){
        	bw.write("impossible");
        }else{
        	bw.write(res+"");
        }
        
        
        br.close();
        bw.flush();
        bw.close();
    }
    
    static class Node implements Comparable<Node>{
    	int x;
    	int dis;
    	public Node() {}
		public Node(int x, int dis) {			
			this.x = x;
			this.dis = dis;
		}  
		@Override
		public int compareTo(Node o) {
			// TODO Auto-generated method stub
			return this.dis-o.dis;
		}
    }
    
    static void add(int a,int b,int c){
    	e[id]=b;    	
    	ne[id]=h[a];  
    	w[id]=c;
    	h[a]=id++;
    }
   
}

最小生成树2(模板)

给定一个包含 nn 个顶点和 mm 条边的无向图。图中可能存在重边和自环,且边的权值可能为负数。你需要求出最小生成树(MST)的边权重之和。如果无法构造最小生成树,则输出 "impossible"。

最小生成树:在一个无向图中,由 nn 个顶点和 n−1n−1 条边构成的连通子图,且该子图的边权重之和最小。

如果图不连通,无法形成最小生成树。

输入格式

第一行输入二个正整数 n,mn,m。

接下来 mm 行,每行输入 33 个正整数 a,b,ca,b,c。表示点 aa 到点 bb 存在一条无向边,权值为 cc。

2≤n≤105,1≤m≤2×105,1≤a,b≤n,1≤c≤1042≤n≤105,1≤m≤2×105,1≤a,b≤n,1≤c≤104。

输出格式

输出一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出 "impossible"。

样例输入

复制代码
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4

样例输出6

复制代码
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.*;


public class Main {

    static int N=2*100010;     
       
    static int n,m;
    static int id=1;
    
    static Node node[]=new Node[N];
    static int p[]=new int[N];//并查集判断有没有环
   
    
    
   
    
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
    static BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws IOException { 
    	
        StringTokenizer st=new StringTokenizer(br.readLine());
        n=Integer.parseInt(st.nextToken());  
        m=Integer.parseInt(st.nextToken());  
       
        for (int i = 1; i <= n; i++) {
			p[i]=i;
		}
        PriorityQueue<Node> priorityQueue=new PriorityQueue<>();
        for (int i = 0; i < m; i++) {
        	st=new StringTokenizer(br.readLine());
        	int a=Integer.parseInt(st.nextToken());
        	int b=Integer.parseInt(st.nextToken());
        	int c=Integer.parseInt(st.nextToken());
        	priorityQueue.add(new Node(a,b,c));
		}
        
        int cnt=0;//边数
        int res=0;
        while(cnt<n && !priorityQueue.isEmpty()){
        	Node no=priorityQueue.poll();
        	int a=no.a,b=no.b,c=no.dis;
        	if(find(a)!=find(b)){
        		res+=c;cnt++;
        		union(a,b);
        	}
        }
         
       if(cnt==n-1){
    	   bw.write(res+"");
       }else{
    	   bw.write("impossible");
       }
        
        
        
        br.close();
        bw.flush();
        bw.close();
    }
    
    static void union(int a,int b){
    	int pa=find(a),pb=find(b);
    	p[pa]=pb;
    }
    
    static int find(int u){
    	if(u!=p[u]){
    		p[u]=find(p[u]);
    	}
    	return p[u];
    }
    static class Node implements Comparable<Node>{
    	int a;
    	int b;
    	int dis;
    	public Node() {
			// TODO Auto-generated constructor stub
		}
    	
		public Node(int a, int b, int dis) {		
			this.a = a;
			this.b = b;
			this.dis = dis;
		}
		
		@Override
		public int compareTo(Node o) {
			// TODO Auto-generated method stub
			return dis-o.dis;
		}
    	
    }
    

   
}

最近公共祖先(模板)

问题描述

给定一棵有 NN 个节点的树,每个节点有一个唯一的编号,从 11 到 NN。树的根节点是 11 号节点。接下来,你会得到 QQ 个查询。对于每个查询,你将得到两个节点的编号,你的任务是找到这两个节点的最低公共祖先。

输入格式

第一行包含一个整数 NN,表示树的节点数。

接下来的 N−1N−1 行,每行包含两个整数 UU 和 VV,表示节点 UU 和节点 VV 之间有一条边。

下一行包含一个整数 QQ,表示查询的数量。

接下来的 QQ 行,每行包含两个整数 AA 和 BB,表示你需要找到节点 AA 和节点 BB 的最低公共祖先。

输出格式

对于每个查询,输出一行,该行包含一个整数,表示两个节点的最近公共祖先。

样例输入

复制代码
5
1 2
1 3
2 4
2 5
3
4 5
3 4
3 5

样例输出

复制代码
2
1
1

样例说明

对于第一个查询,44 和 55 的最低公共祖先是 22。

对于第二个查询,33 和 44 的最低公共祖先是 11。

对于第三个查询,33 和 55 的最低公共祖先是 11。

测评数据规模

2≤N≤1052≤N≤105,1≤Q≤1041≤Q≤104,1≤U,V,A,B≤N1≤U,V,A,B≤N,题目保证输入的边形成一棵树。

复制代码
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.*;


public class Main {

    static int N=2*100010;     
       
    static int n,m;
    static int id=1;
    
    static int log2[]=new int[N+1];
    static int dep[]=new int[N];
    static int f[][];
    
    static int h[]=new int[N];
    static int e[]=new int[N];
    static int ne[]=new int[N];
    static int w[]=new int[N];
    
   
    
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
    static BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws IOException { 
    	
        StringTokenizer st=new StringTokenizer(br.readLine());
        n=Integer.parseInt(st.nextToken());  
        for (int i = 1; i < n; i++) {
        	st=new StringTokenizer(br.readLine());
        	int u=Integer.parseInt(st.nextToken()),v=Integer.parseInt(st.nextToken());
        	add(u,v);add(v,u);
		}
        log2[1]=0;
        for (int i = 2; i < N; i++) {
			log2[i]=log2[i/2]+1;
		}
        m=log2[N-1];
        f=new int[N][m+1];
        dfs(1,0);
        st=new StringTokenizer(br.readLine());
        int q=Integer.parseInt(st.nextToken());  
        for (int i = 0; i < q; i++) {
        	st=new StringTokenizer(br.readLine());
			int u=Integer.parseInt(st.nextToken()),v=Integer.parseInt(st.nextToken());
			if(u==v)bw.write(u+"");
			else{
				if(dep[u]<dep[v]){//设定u的深度更大
					int t=u;u=v;v=t;
				}
				for (int j = m-1; j >= 0; j--) {
					if(dep[f[u][j]]>=dep[v])u=f[u][j];
				}
				if(u==v){
					bw.write(u+"\n");
				}else{
					for (int j = m-1; j >= 0; j--) {
						if(f[u][j]!=f[v][j]){
							u=f[u][j];
							v=f[v][j];
						}
					}
					bw.write(f[u][0]+"\n");
				}
			
			}
		}
        
        br.close();
        bw.flush();
        bw.close();
    }
    
    
    static void dfs(int u,int p){
    	dep[u]=dep[p]+1;
    	f[u][0]=p;
    	//2^(i)=2^(i-1)+2^(i-1)
    	for (int i = 1; i < m; i++) {
			f[u][i]=f[f[u][i-1]][i-1];
		}
    	for (int i = h[u]; i>0; i=ne[i]) {
			int son=e[i];
			if(son==p)continue;
			dfs(son, u);
		}
    }
    
    
    static void add(int a,int b){
    	e[id]=b;    	
    	ne[id]=h[a];  
    	h[a]=id++;
    }
   
}
相关推荐
这就是佬们吗2 小时前
Python入门⑤-异常处理、文件操作与实战项目
开发语言·数据库·python·算法·pycharm
LONGZETECH2 小时前
新能源汽车充电设备装配与调试仿真教学软件 技术架构与核心实现解析
大数据·算法·3d·unity·架构·汽车
自学小白菜2 小时前
关于提升机器学习算法做预测回归任务精度的方法分享
算法·机器学习·回归·提升精度
学废了wuwu3 小时前
从入门到实战:深入浅出模型压缩三大核心——剪枝、彩票假设与知识蒸馏
人工智能·算法·剪枝
小肝一下3 小时前
3. 单链表
c语言·数据结构·c++·算法·leetcode·链表·dijkstra
劈星斩月3 小时前
监督学习算法 之 决策树
学习·算法·决策树
学计算机的计算基3 小时前
操作系统内存管理全解:虚拟内存、页表、COW、malloc、OOM一篇搞定
java·笔记·算法
tachibana23 小时前
hot100 前 K 个高频元素(347)
java·数据结构·算法·leetcode
To_OC11 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode