最小生成树模板(prim + kruskal + prim堆优化)

最小生成树模板(prim + kruskal + prim堆优化)

prim适用于稠密图,kruskal适用于稀疏图
prim是以更新过的结点连边找最小值,kruskal是将边排序后从小到大选值

一.prim算法

hihocoder #1097 : 最小生成树一·Prim算法

1.利用邻接矩阵存储点与点之间的距离,例如:u -> v 距离为20,那么dist[u][v] = 20;
2.从起点出发,利用mincost[i]记录到第i个点的距离,并且将mincost[起点] = 0,其余赋值为INF
3.贪心的将距离集合(这里的集合是一个假想状态,可以认为是更新过的最短距离的点的集合)
最近的点u加入集合,然后将used[u] = 1,并且更新u附近的点的mincost[]
4.选择下一个离集合最近的且没被用过的点,重复第三步,直到所有联通点都被选择到就退出

code:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;

int n,mp[maxn][maxn],mincost[maxn],ans;
bool vis[maxn];

void prim()
{
	for(int i = 1; i <= n; i++)		mincost[i] = INF,vis[i] = false;
	mincost[1] = 0;
	ans = 0;
	
	while(1){
		int v = -1;
		for(int i = 1; i <= n; i++){
			if(!vis[i] && (v == -1 || mincost[i] < mincost[v]))
				v = i;
		}
		
		if(v == -1)		break;
		vis[v] = true;
		ans += mincost[v];
		for(int i = 1; i <= n; i++)
			mincost[i] = min(mincost[i],mp[v][i]);
	}
}

int main()
{
	cin>>n;
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= n; j++)
			cin>>mp[i][j];
	}
	
	prim();
	
	cout<<ans<<endl;
	return 0;
}

二.kruskal算法

hihocoder #1098 : 最小生成树二·Kruscal算法

1.利用邻接表记录边的信息,并且按照边的权值的顺序从小到大排序
2.选择当前最小权值边,判断其两端的点是否属于同一个联通分量里面,这里使用并查集来判断和合并
3.假如不是属于同一个联通分量,就把他们两个点加在一个联通分量里,并且ans += 边的权值
4.重复2、3步,直到所有边都被判断了一次

code:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5 + 10;

int n,m,fa[maxn],ans;
struct edge{
	int u,v,cost;
};
edge e[1000010];
bool cmp(const edge &e1, const edge &e2)
{
	return e1.cost < e2.cost;
}

void init()
{
	ans = 0;
	for(int i = 1; i <= n; i++)
		fa[i] = i;
}

int find(int x)
{
	return x == fa[x] ? x : fa[x] = find(fa[x]);
}

bool merge(int x,int y)
{
	int xx = find(x);
	int yy = find(y);
	
	if(xx == yy)	return false;
	fa[yy] = xx;
	return true;
}

void kr()
{
	sort(e+1,e+1+m,cmp);
	init();
	
	for(int i = 1; i <= m; i++)
	{
		edge temp = e[i];
		if(merge(temp.u,temp.v))
			ans += temp.cost;
	}
}

int main()
{
	cin>>n>>m;
	for(int i = 1; i <= m; i++)
		cin>>e[i].u>>e[i].v>>e[i].cost;
	
	kr();
	
	cout<<ans<<endl;
	return 0;
}

三.prim + 堆优化 + 链式前向星

hihocder #1109 : 最小生成树三·堆优化的Prim算法

1.其基本思路与prim一样,不过从邻接矩阵记录->链式前向星,然后用优先队列来维护mincost

code:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e6 + 10;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;

struct edge{
	int to,dis,next;
}e[maxn<<1];

int n,m,head[N],dis[N],cnt,num,sum;
bool vis[maxn];

void add(int u,int v,int d)
{
	e[++cnt].dis = d;
	e[cnt].to = v;
	e[cnt].next = head[u];
	head[u] = cnt;
}

struct node{
	int index,dist;
	node(int a,int b){
		index = a,dist = b;
	}
	bool operator < (const node &x) const{
		return dist > x.dist;
	}
};

void prim()
{
	for(int i = 1; i <= n; i++)		dis[i] = INF,vis[i] = false;
	dis[1] = 0;
	
	priority_queue <node> q;
	q.push(node(1,0));
	
	int num = 0;
	
	while(!q.empty() && num < n)
	{
		node temp = q.top();
		q.pop();
		
		int x = temp.index, d = temp.dist;
		if(vis[x])	continue;
		vis[x] = true;
		num++;
		sum += d;
		for(int i = head[x]; i ; i = e[i].next){
			int y = e[i].to;
			if(dis[y] > e[i].dis){
				dis[y] = e[i].dis;
				q.push(node(y,dis[y]));
			}
		}
	}
}

int main()
{
	cin>>n>>m;
	for(int i = 1; i <= m; i++){
		int u,v,d;
		cin>>u>>v>>d;
		add(u,v,d);
		add(v,u,d);
	}
	
	prim();
	
	cout<<sum<<endl;
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用C语言实现Kruskal算法Prim算法求解最小生成树的代码: Kruskal算法: ```c #include <stdio.h> #include <stdlib.h> #define MAX_VERTICES 100 #define MAX_EDGES 100 typedef struct edge { int start, end, weight; } Edge; int parent[MAX_VERTICES]; int find(int i) { while (parent[i]) i = parent[i]; return i; } void unionSet(int i, int j) { if (i != j) parent[j] = i; } void kruskal(Edge edges[], int n, int m) { int i, j, k, sum = 0; for (i = 1; i <= n; i++) parent[i] = 0; for (i = 0; i < m; i++) { int start = edges[i].start; int end = edges[i].end; int weight = edges[i].weight; int x = find(start); int y = find(end); if (x != y) { unionSet(x, y); printf("(%d, %d) %d\n", start, end, weight); sum += weight; } } printf("Weight of MST is %d\n", sum); } int main() { int n, m, i; Edge edges[MAX_EDGES]; printf("Enter number of vertices: "); scanf("%d", &n); printf("Enter number of edges: "); scanf("%d", &m); printf("Enter details of edges (start, end, weight):\n"); for (i = 0; i < m; i++) { scanf("%d %d %d", &edges[i].start, &edges[i].end, &edges[i].weight); } kruskal(edges, n, m); return 0; } ``` Prim算法: ```c #include <stdio.h> #include <stdlib.h> #include <limits.h> #define MAX_VERTICES 100 int graph[MAX_VERTICES][MAX_VERTICES]; int visited[MAX_VERTICES]; int parent[MAX_VERTICES]; int key[MAX_VERTICES]; void prim(int n) { int i, j, k, min, sum = 0; for (i = 1; i <= n; i++) { visited[i] = 0; key[i] = INT_MAX; } key[1] = 0; parent[1] = -1; for (i = 1; i <= n; i++) { min = INT_MAX; for (j = 1; j <= n; j++) { if (!visited[j] && key[j] < min) { min = key[j]; k = j; } } visited[k] = 1; for (j = 1; j <= n; j++) { if (graph[k][j] && !visited[j] && graph[k][j] < key[j]) { parent[j] = k; key[j] = graph[k][j]; } } } printf("Edges of MST:\n"); for (i = 2; i <= n; i++) { printf("(%d, %d)\n", parent[i], i); sum += graph[i][parent[i]]; } printf("Weight of MST is %d\n", sum); } int main() { int n, i, j; printf("Enter number of vertices: "); scanf("%d", &n); printf("Enter adjacency matrix of graph:\n"); for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { scanf("%d", &graph[i][j]); } } prim(n); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值