kruskal和prim算法如何實現最小生成樹

kruskal和prim算法是用來求最小生成樹的算法,那什麼是最小生成樹呢?
最小生成樹是一副連通加權無向圖中一棵權值最小的生成樹,也就是圖中包含全部節點且權值和最小的連通子圖。

kruskal和prim算法講解

對於kruskal和prim算法的講解這裏有個秒懂視頻,講解的很詳細,可以參考下。
kruskal和prim算法秒懂視頻

kruskal算法實現

步驟:

  1. 將圖中的所有邊取出並且按權值由小到大排序
  2. 將已排好序的邊從小到大依次還原,若還原的過程中出現環,則捨棄該邊
  3. 重複步驟2直到選出N-1條邊爲止
// 針對的對象:無向連通圖
// 返回最小連通圖的路徑值和
const int MAX_E = 8;
const int MAX_V = 6;
struct edge { int u, v, cost; }; // 表示邊e=(u, v), 權值爲cost
edge es[MAX_E];
bool cmp(const edge& e1, const edge& e2)
{
	return e1.cost < e2.cost;
}

int kruskal()
{
	sort(es, es + MAX_E, cmp); // 按照edge.cost的順序從小到大排列
	UF uf(MAX_V);  // 實例化並查集
	int res = 0;
	for (int i = 0; i < MAX_E; i++) // 如果已經加入n-1條邊了就可以退出了
	{
		edge e = es[i];
		if (!uf.connected(e.u, e.v)) // 判斷u和v是否在同一連通塊,如果連通的話該邊的加入就會導致出現環
		{
			uf.unioned(e.u, e.v); // 連接u和v
			res += e.cost;
		}
	}
	return res;
}

算法本質:貪心算法
適用類型:稀疏圖(對邊的操作較多)
時間複雜度:O(NlogN)

prim算法實現

步驟:

  1. 選取一個開始頂點,將圖分爲包含該頂點的選擇區域和除該頂點外的未選擇區域
  2. 在連接選擇區域未選擇區域的邊中選取權值最小的邊,並將該邊中頂點沒有在未選擇區域中的點加入到選擇區域點集中
  3. 重複步驟2直到所有的點都加入到選擇區域
const int MAX_V = 6;
int cost[MAX_V][MAX_V] = {
		{0,4,2,INT_MAX,INT_MAX,INT_MAX},
		{4,0,1,3,INT_MAX,INT_MAX},
		{2,1,0,5,1,INT_MAX},
		{INT_MAX,3,5,0,2,1},
		{INT_MAX,INT_MAX,1,2,0,INT_MAX},
		{INT_MAX,INT_MAX,INT_MAX,1,INT_MAX,INT_MAX}
}; // cost[u][v]表示邊e=(u,v)的權值(不存在的情況下設爲INF )

int mincost[MAX_V]; // 保存連接兩個區域的邊的最小權值
int parent[MAX_V];	// 節點i的父節點
bool vis[MAX_V];	// 頂點i是否包含在集合中

int prim(int s = 0)
{
	// 初始化
	for (int i = 0; i < MAX_V; i++)
	{
		mincost[i] = INT_MAX;
		vis[i] = false;
	}
	mincost[s] = 0;
	vis[s] = true;
	int sumcost = 0;

	int v = s; // 表示新加入的結點,注意:後面導致mincost和parent更新的原因就是因爲新節點v的加入
	while (true)
	{
		// 1. 更新連接兩個區域邊的信息(update)
		for (int i = 0; i < MAX_V; i++)
		{
			if (!vis[i] && cost[v][i] < mincost[i])
			{
				mincost[i] = cost[v][i]; // 更新連接兩個區域的邊的最小權值
				parent[i] = v;	// 更新父節點
			}
		}
		// 2. 找連接兩個區域的最小權邊上的沒有訪問的頂點(scan)
		v = -1;
		for (int i = 0; i < MAX_V; i++)
		{
			if (!vis[i] && (v == -1 || mincost[v] > mincost[i])) v = i;
		}
		if (v == -1) break; // 所有的節點被訪問
		// 3. 添加節點到集合(add)
		vis[v] = true;
		sumcost += mincost[v];
	}
	return sumcost;
}

算法本質:動態規劃算法
適用類型:稠密疏圖(對頂點的操作較多)
時間複雜度:O(N^2)
該算法還可以用堆優化,時間複雜度爲O(NlogN)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章