最小生成樹------克魯斯卡爾演算法(並查集、sort)
阿新 • • 發佈:2019-01-08
1.並查集
用法:一個方便歸類的演算法。。。
將一個複雜的圖轉換成一個公共父節點的圖(如圖所示)
具體程式碼:
int find(int x) //並查集
{
int r=x,i=x,temp;
if (tree[r]==r)
return r;
while (tree[r]!=r) //r 找到 最.根節點
r=tree[r];
while (i!=r) //全部變成跟節點
{
temp=tree[i]; //temp 臨時變數
tree[i]=r;
i=temp;
}
return r;
}
2.sort排序
標頭檔案:algorithm
基礎用法:從小到大排序:sort(a,a+n); (n指陣列a的大小)
高尚用法:sort(a,a+n,compare);
其中compare是個bool函式(注意:不能用 '<=' 或 '>=')
bool compare(node e1,node e2) //sort排序---比較函式
{
return e1.weight<e2.weight;
}
3.克魯斯卡爾演算法
好了。。。終於到重點了。。。
首先,記錄是以邊記錄
然後
用sort從小到大排序一波邊的權值大小
接著
從小到大依次選邊
如果這條邊與原來選擇的邊構成了環,就不選這條(continue)
ps:是否構成環可用並查集完成
程式碼獻上:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; struct node { int from,end,weight; }; const int maxSize=200000; int n,m; int tree[maxSize+5]; node edge[maxSize+5]; bool compare(node e1,node e2) //sort排序---比較函式 { return e1.weight<e2.weight; } int find(int x) //並查集 { int r=x,i=x,temp; if (tree[r]==r) return r; while (tree[r]!=r) //r 找到 最.根節點 r=tree[r]; while (i!=r) //全部變成跟節點 { temp=tree[i]; //temp 臨時變數 tree[i]=r; i=temp; } return r; } void Kruskal() { int i,sum,tot,fx,fy; tot=1; sum=0; i=0; while (tot<n) { fx=find(edge[i].from); fy=find(edge[i].end); if (fx!=fy) { tree[fx]=fy; //並查集合並 (這裡是最.根節點的合併!!!) tot++; sum+=edge[i].weight; } i++; } printf("%d\n",sum); } int main() { int i,x,y,z; freopen("a.txt","r",stdin); scanf("%d%d",&n,&m); for (i=0;i<m;i++) { scanf("%d%d%d",&x,&y,&z); edge[i].from=x; edge[i].end=y; edge[i].weight=z; } sort(edge,edge+m,compare); for (i=1;i<=n;i++) tree[i]=i; Kruskal(); return 0; }