kruskal 算法

Kruskal 算法链表基本模板:

#include <iostream>
using namespace std;

typedef struct node
{
	int l;
	int r;
	int length;
	struct node *next;
}Node,*LNode;      // 定义结构体
void Init(LNode &L)   // 初始化结构体
{
	L=new Node;
	L->next=NULL;
	L->l=0;
	L->r=0;
	L->length=0;
}
//将权值 从小到大 插入链表。
void Create(LNode &L,int i,int j,int len) 
{
    Node *p,*g;
	p=L->next;
	g=L;
	while(p)
	{     
		if(len<p->length)
			break;
		g=p;
		p=p->next;
	}
	Node *q;
	q=new Node;
	q->next=g->next;
	q->length=len;
	q->l=i;
	q->r=j;
	g->next=q;
}


/*
void print(LNode L) // 是否排序
{
	Node *p;
	p=L->next;
	while(p)
	{
		cout<<p->length<<" ";
		p=p->next;
	}
	cout<<endl;
}*/
#define MAX 1000
int main()
{
	LNode L;
	
//	freopen("k.txt","r",stdin);
	int set[MAX];
	int n,i,j,e;
	while(cin>>n)
	{
		Init(L);
		for(i=1;i<=n;i++) // 将数组初始化
			set[i]=i;
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
			{
				cin>>e;
				if(e && i>j)  //下三角形不为0时按顺序插入链表中
				{
					Create(L,i,j,e);
				}
			}
		//	print(L);
			int sum=0; // 边的总和
			Node *p;
			p=L->next;
			int v=0; //边数
			while(p)
			{
				//	print(L);
				int t1=p->l,t2=p->r;
				if(set[t1]!=set[t2]) 
				{
					int d=set[t1];  //  特别注意,这里要保存后在改变,被这里坑了好久。
						for(i=1;i<=n;i++)
							if(set[t1]==set[i])
							set[i]=set[t2];	
					for(i=1;i<=n;i++)
						if(d==set[i])
							set[i]=set[t1];
					sum+=p->length;
					v++;
					if(v==n-1)
						break;
				}
				p= p->next;
			}
			cout<<sum<<endl;
			
	}
	
	return 0;
}
/*
6
0 6 1 5 0 0
6 0 5 0 3 0
1 5 0 5 6 4
5 0 5 0 0 2
0 3 6 0 0 6
0 0 4 2 6 0*/
/*
4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0*/

借用大神代码:

 用结构体做的kruskal 算法

#include <iostream>
#include <algorithm>
using namespace std;

int n,k,Vexset[110];

struct P{
	int Head,Tail;
	int lowcost;
}Edge[11000];

bool cmp(P a,P b){
	return a.lowcost<b.lowcost;
}

void Kruskal(){
	sort(Edge,Edge+k,cmp);
	/*int i,j;
	for(i=0;i<k;i++)
	cout<<Edge[i].lowcost<<endl;
	*/
	int i,s=0,c=1;
	for(i=0;i<n;i++)
		Vexset[i]=i;
	for(i=0;i<k;i++){
		int vs1,vs2;
		vs1=Vexset[Edge[i].Head];
		vs2=Vexset[Edge[i].Tail];
		if(vs1!=vs2){
			//cout<<Edge[i].Head<<' '<<Edge[i].Tail<<endl;
			s+=Edge[i].lowcost;
			c++;
			if(c==n)
				break;
			for(int j=0;j<n;j++){
				if(Vexset[j]==vs2){
					Vexset[j]=vs1;
				}
			}
		}
	}
	cout<<s<<endl;
}
int main(){
	while(cin>>n){
		int i,j,d;
		k=0;
		for(i=0;i<n;i++){
			for(j=0;j<n;j++){
				cin>>d;
				if(i>j&&d){
					Edge[k].Head=i;
					Edge[k].Tail=j;
					Edge[k].lowcost=d;
					k++;
				}
			}
			
		}
		Kruskal();
	}
	return 0;
}


题目: http://poj.org/problem?id=1258


<think>好的,用户想了解Kruskal算法的实现和原理,特别是关于最小生成树的部分。我需要先回忆一下Kruskal算法的基本概念和步骤。首先,Kruskal算法是一种贪心算法,用于在连通图中找到最小生成树。它的核心思想是按边的权重从小到大排序,然后逐步选择不形成环的边,直到所有顶点都连通。 接下来,用户可能需要知道具体的实现步骤。我应该分点说明:第一步是排序所有边,第二步是使用并查集来检测环。需要解释并查集的作用,即在合并两个集合时判断是否形成环。这部分需要详细一点,因为并查集对于不熟悉的用户来说可能不太容易理解。 然后,关于时间复杂度,Kruskal算法的时间复杂度主要是由排序和并查集操作决定的。排序通常是$O(E \log E)$,而并查集操作近似线性,所以总的时间复杂度是$O(E \log E + E \alpha(V))$,其中$\alpha$是阿克曼函数的反函数,增长缓慢。这部分可能需要简化说明,让用户更容易理解。 用户提供的引用资料中提到了Kruskal算法的实现细节,比如边排序和环检测,我需要确保我的回答涵盖这些点,并适当引用。例如,引用[1]提到使用并查集判断环,引用[2]讨论了贪心策略和边排序,这些都需要整合到回答中。 另外,用户可能需要代码示例来更好地理解算法实现。根据引用[3]和[4],C++的实现代码可能有用,但用户的问题中没有指定语言,所以可以考虑提供一个通用的伪代码或Python示例。但根据用户提供的示例中的Python代码,可能更适合用Python示例,但引用中的代码是C++,需要确认。不过用户的问题可能更关注原理,代码示例可以辅助说明。 可能还需要对比Prim算法,但用户没有提到,所以暂时不需要展开。但相关问题可以提到,作为扩展问题。 最后,生成的相关问题需要围绕Kruskal算法的优化、应用场景、与其他算法的比较等。比如,如何优化排序过程,或者在实际应用中的案例。 现在需要确保回答结构清晰,分步骤解释原理,代码示例正确,引用适当。同时,检查LaTeX格式是否正确,所有数学表达式用$...$,独立公式用$$...$$,比如时间复杂度部分可能需要独立公式。 总结,回答的结构应该是: 1. 算法原理(贪心、步骤) 2. 实现细节(排序、并查集) 3. 时间复杂度分析 4. 代码示例(Python或C++) 5. 引用整合 6. 相关问题生成 需要确保每个部分自然衔接,引用标识放在相关解释的末尾。例如,在讲解并查集时引用[1]和[4]。 可能还需要注意术语的一致性,比如“连通块”或“集合”在解释过程中的使用。此外,避免过于技术性的术语,用通俗的中文解释,同时保持准确性。</think>### Kruskal算法原理与实现 #### 一、算法原理 Kruskal算法是一种基于**贪心策略**的最小生成树算法,其核心思想是: 1. **边排序**:将图中所有边按权重从小到大排序[^2] 2. **逐条选择**:从最小权重边开始,依次选择不构成环的边加入生成树 3. **终止条件**:当选择的边数达到$n-1$($n$为顶点数)时停止 算法通过**并查集(Union-Find)**数据结构判断是否形成环。当两个顶点属于同一连通分量时,连接它们的边会形成环,此时应舍弃该边[^1][^4]。 #### 二、算法步骤 1. 初始化每个顶点为一个独立连通块 2. 按边权重升序排序 3. 遍历排序后的边: - 若边的两个顶点属于不同连通块: - 合并两个连通块 - 将该边加入最小生成树 4. 重复步骤3直到生成树包含$n-1$条边 时间复杂度为$O(E \log E)$,主要来自排序操作,其中$E$为边数。 #### 三、Python代码实现 ```python class UnionFind: def __init__(self, size): self.parent = list(range(size)) def find(self, x): if self.parent[x] != x: self.parent[x] = self.find(self.parent[x]) return self.parent[x] def union(self, x, y): root_x = self.find(x) root_y = self.find(y) if root_x != root_y: self.parent[root_y] = root_x def kruskal(vertices, edges): edges.sort(key=lambda x: x[2]) uf = UnionFind(vertices) mst = [] for u, v, weight in edges: if uf.find(u) != uf.find(v): uf.union(u, v) mst.append((u, v, weight)) if len(mst) == vertices - 1: break return mst ``` #### 四、关键优化 1. **路径压缩**:在并查集的`find`操作中压缩路径,降低时间复杂度 2. **按秩合并**:在`union`操作中根据树深度决定合并方向[^3] 3. **提前终止**:当已选边数达到$n-1$时立即停止遍历[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值