在學習最小生成樹演算法之前我們先了解一些基本概念
生成樹是乙個連通圖的連通子圖,包含圖中的n個點,n-1條邊。最小生成樹是這n-1條邊的權值之和最小的一顆生成樹。
prim演算法可在加權連通圖里搜尋最小生成樹,通俗來說就是在乙個帶權值的連通圖中保留n-1條邊(這n-1條邊的權值和最小),但依舊使這個圖為連通圖。prim演算法是基於貪心的思想,每次都選擇一條符合條件的權值最小的邊對於的點加入生成樹。
prim演算法的時間複雜度為o(n^2),適合稠密圖
通常最小生成樹問題一般用鄰接矩陣存圖,比較方便
流程為:
首先初始化陣列dis【】、pre【】,dis【i】表示點 i 在生成樹中需要耗費的代價,dis = 0;pre【i】代表生成樹中pre【i】與點 i 相連(前驅),pre = -1,代表沒有前驅,vis【i】 = 1表示以訪問。id1
2345
6vis10
0000
dis061
5inf
infpre
- 1111
1 之後從上表中選乙個dis【】距離最小,且vis【】 = 0 的點,然後用這個點去更新他鄰接點(未訪問)在最小生成樹中的距離,且更新前驅,這裡的點為3
更新上表得id1
2345
6vis10
1000
dis051
564pre
- 1311
3選擇點6,更新其他點id1
2345
6vis10
1001
dis051
264pre
- 1316
3 接下來符合條件的點為4,更新其他陣列id1
2345
6vis10
1101
dis051
264pre
- 1316
3接下來選擇點2,更新資料id1
2345
6vis11
1101
dis051
234pre
- 1316
2接下來是點5,已更新完所有資料,dis【】陣列中衛最小生成樹的權值,pre【】陣列中記錄的是最小生成樹的邊
例題:hdu1102
#includeusing namespace std;
typedef pairpi;
const int inf = 0x3f7f7f7f;
const int n = 105;
int mp[n][n];
int lowcost[n];
int pre[n];
int vis[n];
int n;
int prim(int s)
vis[s] = 1;
pre[s] = -1;
for(int i = 1; i < n; i ++)
}if(pos == -1) return -1;
vis[pos] = 1;
ans += mmin;
for(int j = 1; j <= n; j ++)}}
return ans;
}int main()
printf("%d\n",prim(1));
/* for(int i = 2; i <= n; i ++)
}*/ return 0;
}//hdu1102
在學習這個演算法之前,我們需要先學習一種資料結構:並查集
並查集:.是一種關於集合的操作,能夠快速的找到某個元素所在的集合,而且還能夠實現集合之間的合併。
並查集包含三種操作:
1、初始化操作:最開始將每個元素出事化為乙個集合。pre【i】代表著i點所在的集合,最開始pre【i】 = i;
2、查詢元素所在的集合:也就是查詢這個集合所有元素的祖先
如pre【a】 = b,pre【b】 = c,pre【c】 = d,pre【d】 = d,這裡d就是所有元素的祖先
3、合併操作,合併兩個不同的集合,也就是找到這兩個集合的祖先,使其中乙個祖先指向另乙個集合。
並查集的優化:
這個圖中我們可以看出要找到點a的祖先,需要經過好幾次迴圈,那麼我就可以讓這個集合中的所有元素都直接指向祖先,這樣就可以在下次查詢時o(1)的複雜度就能夠找到。
關鍵**:
int findx(int x)
return x;
}void link(int u, int v)
kruskal演算法是基於貪心的思想,利用並查集實現的,每次選著一條權值最小的符合條件的邊(條件:這條邊的兩個點不再同乙個集合)將其加入生成樹集合
過程:1、將邊按權值大小排序
2、選擇一條權值最小的邊,且這條邊的兩點屬於不同的集合,然後合併這兩個集合
3、重複以上操作直到所有點都屬於乙個集合
例題:hdu1102
#includeusing namespace std;
typedef pairpi;
const int inf = 0x3f7f7f7f;
const int n = 200;
int mp[n][n];
int pre[n];
int n;
struct edge
grap[n*n];
bool cmp(edge a,edge b)
int findx(int x)
return x;
}void link(int u, int v)
int main()
int cnt = 0;
for(int i = 1; i<= n*n; i ++)
}for(int i = 1; i <= n; i ++)
pre[i] = i;
sort(grap,grap+cnt,cmp);
int ans = 0;
for(int i = 0; i < cnt; i ++)
}printf("%d\n",ans);
}return 0;
}//hdu 1102
最小生成樹(prim演算法)
最小生成樹是資料結構中圖的一種重要應用,它的要求是從乙個帶權無向完全圖中選擇n 1條邊並使這個圖仍然連通 也即得到了一棵生成樹 同時還要考慮使樹的權最小。prim演算法要點 設圖g v,e 其生成樹的頂點集合為u。把v0放入u。在所有u u,v v u的邊 u,v e中找一條最小權值的邊,加入生成樹...
最小生成樹 Prim演算法
prim 演算法 以領接矩陣儲存 圖g bool b i 表示頂點i是否被訪問,初始化時候memset b,false,sizeof b b 0 value,表示從第0個節點開始。用value i 表示節點i到最小生成樹a中定點的最小距離。例如value 1 a 0 1 int sum記錄權值和 i...
最小生成樹 prim 演算法
一 演算法描述 假設存在連通帶權圖g v,e 其中最小生成樹為t,首先從圖中隨意選擇一點s屬於v作為起始點,並將其標記後加入集合u 中。然後演算法重複執行操作為在所有v屬於u,u屬於v u的邊 v0,u0 屬於e中找一條代價最小的邊並加入集合t,同時將u0併入u,直到u v為止。這是,t中必有n 1...