最小生成树

定义

  • 在无向图中 生成一棵树,这棵树涵盖所有顶点,且权值之和最小

性质

  • 边数=n-1
  • 对于给定的图,最小生成树可能不唯一,但是权值之和一定唯一
  • 每一个结点都是平等的(因为来源于图)
  • O(v2),可以用堆优化为O(VlogV+E)

代码

邻接矩阵

#include<algorithm>
using namespace std;
const int max_n = 30;
const int INF=0x3fffffff;
int n,G[max_n][max_n];
bool vis[max_n] = { false };
int d[max_n];//距离集合的最短距离
//prim算法
//邻接矩阵
void prim()
{
	fill(d, d + n, INF);
	//选出
	d[0] = 0;
	for (int j = 0; j < n ;j++)
	{
		int u = -1, min = INF;
		//选出最近的
		for (int i = 0; i < n; i++)
		{
			if (vis[i] == false && d[i] < min)
			{
				min = d[i];
				u = i;
			}
		}
		//加入集合 更新
		if (u == -1)return;
		vis[u] = true;
		for (int i = 0; i < n; i++)
		{
			if (vis[i] == false && G[u][i] != INF && d[i] > G[u][i])
			{
				d[i] = G[u][i];
			}
		}
	}
	
}

邻接表

#include<algorithm>
#include<vector>
using namespace std;
//最小生成树:在无向图中 生成一棵树,这棵树涵盖所有顶点,且权值之和最小
//1.边数=n-1
//2.对于给定的图,最小生成树可能不唯一,但是权值之和一定唯一
//3.每一个结点都是平等的(因为来源于图)
const int max_n = 30;
const int INF=0x3fffffff;
int n;
struct  node
{
	int v;
	int dis;
};
vector<node*>Adj[max_n];
bool vis[max_n] = { false };
int d[max_n];//距离集合的最短距离
//prim算法
//邻接表
void prim()
{
	fill(d, d + n, INF);
	d[0] = 0;
	for (int j = 0; j < n - 1; j++)
	{
		int u = -1, min = INF;
		for (int i = 0; i < n; i++)
		{
			if (vis[i] == false && d[i] < min)
			{
				min = d[i];
				u = i;
			}
		}
		if (u == -1)return;
		vis[u] = true;
		for (int i = 0; i < Adj[u].size(); i++)
		{
			int v = Adj[u][i]->v;
			int dis = Adj[u][i]->dis;
			if (vis[v] == false && d[v] > dis)
			{
				d[v] = dis;
			}
		}
	}
	
}

Kruskal算法

  • 加最小边 然后判断有没有环
  • 使用并查集 没有环:两个端点的根节点不同
#include<algorithm>
using namespace std;
const int max_n = 30;
const int max_e = 40;
int father[max_n];
int e,n;
struct edge
{
	int s;
	int d;
	int dis;
};
edge edges[max_e];
bool cmp(edge e1,edge e2)
{
	return e1.dis < e2.dis;
}
//找到根节点
int findFather(int v)
{
	int x = v;
	while (father[x] != x)
	{
		x = father[x];
	}
	return x;
}
//合并两个集合
bool Union(int x, int y)
{
	int fx = findFather(x), fy = findFather(y);
	if (fx != fy)
	{
		father[fy] = fx;
		return true;
	}
	return false;
}
int kruskal()
{
	sort(edges, edges + e, cmp);
	int ans = 0;//权值之和
	int cnt = 0;//边数
	for (int i = 0; i < n; i++)
	{
		father[i] = i;
	}
	for (int i = 0; i < e; i++)
	{
		if (Union(edges[i].s, edges[i].d))//判断有没有环
		{
			ans += edges[i].dis;//选择这条边
			cnt++;
		}
		if (cnt == n - 1)
		{
			break;
		}
	}
	
	return ans;
}
posted @ 2021-09-06 21:36  小帆敲代码  阅读(67)  评论(0编辑  收藏  举报