考研机试 -Kruskal算法

kruskal算法 生成最小生成树:

算法思想: 将边权按由小到大排序, 每次将权重最小的union, 并且记录其权重, 边界条件:

  1. 如果有公共的根节点,则说明成环了 不可,2. 如果并入的边 == 节点个数-1 , 则为最小生成树了,退出循环

1.还是畅通工程_牛客题霸_牛客网 利用并查集和kruskal算法

cpp 复制代码
using namespace std;
const int N = 10010;
int father[N];
int high[N];
void InitTree(int n){
	for(int i = 1;i<=n;i++){
		father[i] = i;
		high[i] = 0;
	}
} 

int FindTree(int u){
	if(u==father[u])
		return u;
	else{
		father[u] = FindTree(father[u]);
		return father[u];
	}
}

void UnionTree(int u,int v){
	int uroot = FindTree(u);
	int vroot = FindTree(v);
	if(uroot!=vroot){
		if(high[uroot]<high[vroot])
			father[uroot] = vroot;
		else if(high[uroot]>high[vroot])
			father[vroot] = uroot;
		else{
			father[vroot] = uroot;
			high[uroot]++;
		}
	}
}
struct Edge{
	int u;
	int v;
	int w;
	Edge(int _u,int _v,int _w){//内置构造函数, 函数名字和结构体名字一致,类内没有返回值 
		u = _u;
		v = _v;
		w = _w; 
	}
};
bool compare(Edge lsh,Edge rsh){
	return lsh.w<rsh.w;//结构体不知道如何比较大小,需要内置 
}
int main(){
	int n;
	while(cin>>n){// 
		if(n==0)
			break;
		vector<Edge> edgeVec;//边数组 
		InitTree(n+1);//初始化为0-n个节点的树 
		for(int i = 0;i<n*(n-1)/2;i++){
			int u,v,w;
			cin>>u>>v>>w;
			Edge e(u,v,w);//Edge 变量 ,变量名e 
			edgeVec.push_back(e); //边压入 
		} 
		//kruskal排序 权重排序 按照边权值由小到大 
		sort(edgeVec.begin(),edgeVec.end(),compare);
		int totalweight = 0;//边权值 
		int curnum = 0;//目前加入的边数 
		for(int i = 0;i<edgeVec.size();i++){//遍历边数组 
			int u = edgeVec[i].u;
			int v = edgeVec[i].v;
			int w = edgeVec[i].w;
			if(FindTree(u)!=FindTree(v)){//不是同一个集合 
				UnionTree(u,v);//合并 
				totalweight+=w;//增加权重 
				curnum++; //增加子图的边 
				
				if(curnum == n-1)//退出边界条件 
					break; 
			} 
		} 
		cout<<totalweight<<endl; 
	}
	return 0;

2.继续畅通工程_牛客题霸_牛客网

怎么样处理已经连接过的路径呢?

利用两次遍历循环,先遍历边数组结构 1.把t==1 的边先合并 2. 在构建一个unbuild数组 ,把t==0的数组合并 。将其排序, 利用kruskal算法,求其权重

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 10010;
int father[N];
int high[N];
void InitTree(int n ){
	for(int i =1;i<=n;i++){
		father[i] = i;
		high[i] = 0;
	}
} 

int FindTree(int u){
	if(u==father[u]) 
		return u;
	else {
		father[u] = FindTree(father[u]);
		return father[u];
	}
}

void UnionTree(int u,int v){
	int uroot = FindTree(u);
	int vroot = FindTree(v);
	if(uroot != vroot){
		if(high[uroot]>high[vroot])
			father[vroot] = uroot;
		else if(high[uroot]<high[vroot])
			father[uroot] = vroot;
		else{
			father[vroot] = uroot;
			high[uroot] ++;
		} 
	}
}

struct Edge{
	int u,v,w,t;
	Edge(int _u,int _v,int _w,int _t){
		u = _u;
		v = _v;
		w = _w;
		t = _t;
	} 
};

bool compare(Edge lsh,Edge rsh){
	return lsh.w<rsh.w; 
}

int main(){
	int n;
	while(cin>>n){
		if(n==0)
		 	break;
		InitTree(n);
		vector<Edge> vecEdge;
		for(int i = 0;i<n*(n-1)/2;i++){
			int a,b,c,d;
			cin>>a>>b>>c>>d;
			Edge e(a,b,c,d);
			vecEdge.push_back(e);
		}
        //先将t==1的合并
		for(auto &e:vecEdge){
			if(e.t ==1)
				UnionTree(e.u,e.v);
		} 
        //构建没有合并的节点数组
		vector<Edge> unbuild;
		for(auto &e:vecEdge){
			if(e.t == 0)
				unbuild.push_back(e);//压入数组
		} 
		//利用kruskal算法,排序
		sort(unbuild.begin(),unbuild.end(),compare);
		
		int totalweight = 0;
		int curnum = 0;
		for(auto &e:unbuild){//遍历unbuild,增加其权值
			if(FindTree(e.u)!= FindTree(e.v)){
				UnionTree(e.u,e.v);
				totalweight += e.w; 
			}
		}
			if(curnum == n-1)
				break;
		cout<<totalweight<<endl;
	} 
	return 0;
}

.3Freckles_牛客题霸_牛客网

题目意思: 输入n个点的坐标 ,求生成最小子树的最短路径,我们手动求解dist

dist[vec[i],vec[j]] 传入的是整个point节点

思路:整体思路 并查集加kruskal算法

细节:

定义point 结构体存放 坐标

定义Edge 结构体 存放 遍历的节点去向, from to 以及权值

用函数dist () 计算距离

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int father[N];
int high[N];

void InitTree(int n){
	for(int i = 1;i<=n;i++){
		father[i] = i;
		high[i] = 0;
	}
} 

int FindTree(int u){
	if(u == father[u])
		return u;
	else{
		father[u] = FindTree(father[u]);
		return father[u];
	}
}

void UnionTree(int u,int v){
	int uroot = FindTree(u);
	int vroot = FindTree(v);
	if(uroot!=vroot){
		if(high[uroot]>high[vroot])
			father[vroot] = uroot;
		else if(high[uroot] < high[vroot])
			father[uroot] = vroot; 
		else{
			father[vroot] = uroot;
			high[uroot]++; 
		}
	}
}

struct Point{
	float x,y;
	Point (float a, float b){
		x = a;
		y = b;
	}	//内嵌函数 
};

struct Edge{
	float from,to,w;
	Edge(float _f,float _t , float _w){
		from =_f;
		to = _t;
		w = _w;
	}//内嵌函数 
};

bool compare(Edge x,Edge y){
	return x.w<y.w; 
}

float dist(Point x, Point y){
	return pow((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y),0.5);//计算距离 
} 

int main(){
	int n;
	while(cin>>n){
		InitTree(n);
		vector<Point> vec;
		for(int i =0;i<n;i++){
			float a,b;
			cin>>a>>b;
			Point p(a,b);
			vec.push_back(p);//压入坐标 
		}
		vector<Edge> graph;
		for(int i = 0;i<vec.size();i++){
			for(int j = i+1;j<vec.size();j++){
				graph.emplace_back(i+1,j+1,dist(vec[i],vec[j])); //压入图中, 遍历点与点之间的距离 
			}
		}
		sort(graph.begin(),graph.end(),compare);//排序由小到大 
		double res= 0.0;
		for(auto &e: graph){//遍历 
			if(FindTree(e.from)!= FindTree(e.to)){//判断不为公共节点 
				UnionTree(e.from,e.to);
				res+=e.w;
			}
		}
		printf("%.2f\n",res); 
	} 
	return 0;
}

j

相关推荐
big_rabbit05022 小时前
[算法][力扣283]Move Zeros
算法·leetcode·职场和发展
小资同学2 小时前
考研机试动态规划 线性DP
算法·动态规划
listhi5202 小时前
两台三相逆变器并联功率分配控制MATLAB实现
算法
Evand J2 小时前
【IMM】非线性目标跟踪算法与MATLAB实现:基于粒子滤波的交互式多模型,结合CV和CT双模型对三维空间中的机动目标进行高精度跟踪
算法·matlab·目标跟踪·pf·粒子滤波·imm·多模型
重生之后端学习2 小时前
64. 最小路径和
数据结构·算法·leetcode·排序算法·深度优先·图论
We་ct2 小时前
LeetCode 212. 单词搜索 II:Trie+DFS 高效解法
开发语言·算法·leetcode·typescript·深度优先·图搜索算法·图搜索
样例过了就是过了2 小时前
LeetCode热题100 路径总和 III
数据结构·c++·算法·leetcode·链表
lxh01132 小时前
函数防抖题解
前端·javascript·算法
再难也得平2 小时前
力扣41. 缺失的第一个正数(Java解法)
数据结构·算法·leetcode