最小生成树—— Prim算法 ▪ Kruskal算法C语言实现

在一给定的 无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此 的权重,若存在 T 为 E 的 子集(即)且为无循环图,使得
的 w(T) 最小,则此 T 为 G 的 最小生成树
最小生成树其实是 最小权重生成树的简称。
许多应用问题都是一个求无向连通图的最小生成树问题。例如:要在n个 城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同;另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树。


Prim算法

就是点优先,原始集合里面存放所有的点,目标集合最初为空,先任意从原始集合取一个点放在目标集合,此时开始搜索,原始集合到目标集合最近的一个点,找到后将他放入目标集合,更新原始集合中的点到目标集合的距离,一直将原始集合中的点全部加入到目标集合中,完成搜索。


#include<stdio.h>
int arr[101][101];
int main(){
	int n,ttt = 0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			scanf("%d",&arr[i][j]);
		}
	}	
	for(int j=2;j<=n;j++){
		int min = 100000000;
		int index = 0;
		for(int i=1;i<=n;i++){
			if(arr[1][i]==0) continue;
			if(arr[1][i]<min){
				min = arr[1][i];
				index = i;
			}
		}
		ttt += arr[1][index];
		for(int i=1;i<=n;i++){
			arr[1][i] = arr[1][i]<arr[index][i]?arr[1][i]:arr[index][i];
		}
	}
	printf("%d\n",ttt);
	return 0;
}



Kruskal算法

就是边优先,先将每一条边从大到小排序,每次去最小的一条边连接两个点,但是需要判断,是否形成回路。


#include<iostream>
#include<stdio.h>
#include<cstdlib>
using namespace std;
struct eg{
	int start;
	int end;
	int weight;
};
int addNum = 0;
eg arr[5060];
int cmp(const void *v1,const void *v2){
	eg t1 = *(eg*)v1;
	eg t2 = *(eg*)v2;
	return t1.weight-t2.weight;
}
int main(){
	int n,index=0,ttt;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(j<=i){
				scanf("%d",&ttt);
			}else{
				scanf("%d",&arr[index].weight);
				arr[index].start = i;
				arr[index].end = j;
				index++;
			}
		}
	}
	int num = n*(n-1)/2;
	qsort(arr,num,sizeof(eg),cmp);
	int countW = 0;
	int x[101];
	for(int i=1;i<=100;i++){
		x[i] = i;
	}
	
	for(int i=0;i<num&&addNum<n;i++){
		int k,g;
		for(k=arr[i].start;x[k]!=k;k=x[k])  //判断线段的起始点所在的集合  
            x[k]=x[x[k]];  
        for(g=arr[i].end;x[g]!=g;g=x[g])  //判断线段的终点所在的集合  
            x[g]=x[x[g]];  
        if(k!=g)  //如果线段的两个端点所在的集合不一样  
        {  
            x[g]=k;
            countW+=arr[i].weight;
            addNum++;  
            //printf("最小生成树中加入边:%d %d/n",a[i].m,a[i].n);  
        }
	}
	printf("%d\n",countW);
	return 0;
}


样例输入

4

0  4  9 21

4  0  8 17

9  8  0 16

21 17 16  0



样例输出
28


  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以为您介绍一下Prim算法Kruskal算法,并提供C语言实现代码。 首先,Prim算法是一种贪心算法,它从一个源节点开始,逐步扩大生成树的规模,直到包含图中所有节点。在每一步中,Prim算法选择当前生成树外与生成树内节点距离最短的边,将其加入生成树中。这个过程一直重复,直到生成树包含了所有节点。 其次,Kruskal算法也是一种贪心算法,它将所有边按照权值从小到大排序,然后依次将边加入生成树中,如果加入这条边不会形成环,就将其加入生成树中。这个过程一直重复,直到生成树包含了所有节点。 下面是Prim算法Kruskal算法C语言实现代码: Prim算法实现代码: ```c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define INF 999999 int n; // 节点数 int graph[100][100]; // 图的邻接矩阵 int dist[100]; // 到生成树的最短距离 bool visited[100]; // 是否已访问 int parent[100]; // 最小生成树的父节点 int prim() { // 初始化 for (int i = 1; i <= n; i++) { dist[i] = INF; visited[i] = false; } dist[1] = 0; parent[1] = -1; // 重复 n-1 次 for (int i = 1; i < n; i++) { // 找到到生成树距离最小的节点 u int u = -1; for (int j = 1; j <= n; j++) { if (!visited[j] && (u == -1 || dist[j] < dist[u])) { u = j; } } visited[u] = true; // 更新到生成树的距离和父节点 for (int v = 1; v <= n; v++) { if (!visited[v] && graph[u][v] < dist[v]) { dist[v] = graph[u][v]; parent[v] = u; } } } // 计算最小生成树的权值和 int sum = 0; for (int i = 1; i <= n; i++) { if (parent[i] != -1) { sum += graph[i][parent[i]]; } } return sum; } int main() { // 输入图的邻接矩阵和节点数 scanf("%d", &n); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { scanf("%d", &graph[i][j]); } } int minWeight = prim(); printf("最小生成树的权值和为 %d\n", minWeight); return 0; } ``` Kruskal算法实现代码: ```c #include <stdio.h> #include <stdlib.h> #define MAX 100 int n; // 节点数 int parent[MAX]; // 并查集数组 int graph[MAX][MAX]; // 图的邻接矩阵 // 并查集查找 int find(int x) { if (parent[x] == x) { return x; } return parent[x] = find(parent[x]); } // 并查集合并 void merge(int x, int y) { int px = find(x); int py = find(y); if (px != py) { parent[px] = py; } } // Kruskal算法 int kruskal() { // 初始化并查集 for (int i = 1; i <= n; i++) { parent[i] = i; } // 将所有边按照权值从小到大排序 int edges[MAX*MAX][3]; int count = 0; for (int i = 1; i <= n; i++) { for (int j = i+1; j <= n; j++) { if (graph[i][j] != 0) { edges[count][0] = i; edges[count][1] = j; edges[count][2] = graph[i][j]; count++; } } } for (int i = 0; i < count-1; i++) { for (int j = i+1; j < count; j++) { if (edges[i][2] > edges[j][2]) { int temp[3]; temp[0] = edges[i][0]; temp[1] = edges[i][1]; temp[2] = edges[i][2]; edges[i][0] = edges[j][0]; edges[i][1] = edges[j][1]; edges[i][2] = edges[j][2]; edges[j][0] = temp[0]; edges[j][1] = temp[1]; edges[j][2] = temp[2]; } } } // 依次加入边,直到生成树包含所有节点 int sum = 0; for (int i = 0; i < count; i++) { int u = edges[i][0]; int v = edges[i][1]; if (find(u) != find(v)) { merge(u, v); sum += edges[i][2]; } } return sum; } int main() { // 输入图的邻接矩阵和节点数 scanf("%d", &n); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { scanf("%d", &graph[i][j]); } } int minWeight = kruskal(); printf("最小生成树的权值和为 %d\n", minWeight); return 0; } ``` 以上是Prim算法Kruskal算法C语言实现代码,希望能够帮到您。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值