最小生成樹有兩個算法,一個是prim,一個是kruskarl徙歼。prim算法就相當于以點為主,來找最小生成樹
而kruskarl算法就是著眼于邊了
核心思想
1.將所有邊按從小到大排序
2.枚舉某一條邊鳖枕,若與邊相連的兩個點不在同一個集合魄梯,就合并這兩個點,不然就跳過(此處會用到并查集)宾符,不會并查集的話可以看看我以前寫的并查集
3.(重點)若邊數=點數-1酿秸,則最小樹成功生成。原理:這其實就是數學魏烫,一條邊有兩條端點辣苏,兩條邊因為共用一個端點,所以是三個端點(如下)
.___.___.
這就是三個點時邊的情況
實現
原題
文字稿如下
題目描述
如題哄褒,給出一個無向圖稀蟋,求出最小生成樹,如果該圖不連通呐赡,則輸出orz
輸入輸出格式
輸入格式:
第一行包含兩個整數N糊治、M,表示該圖共有N個結點和M條無向邊罚舱。(N<=5000井辜,M<=200000)
接下來M行每行包含三個整數Xi绎谦、Yi、Zi粥脚,表示有一條長度為Zi的無向邊連接結點Xi窃肠、Yi
輸出格式:
輸出包含一個數,即最小生成樹的各邊的長度之和刷允;如果該圖不連通則輸出orz
輸入輸出樣例
輸入樣例#1: 復制
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
輸出樣例#1: 復制
7
說明
時空限制:1000ms,128M
數據規(guī)模:
對于20%的數據:N<=5冤留,M<=20
對于40%的數據:N<=50,M<=2500
對于70%的數據:N<=500树灶,M<=10000
對于100%的數據:N<=5000纤怒,M<=200000
我用了一個結構體來存儲(也可以用鏈式前向星)
const int M=200100;
struct node{
int x;//出發(fā)節(jié)點
int y;//到達節(jié)點
int w;//邊長度
}a[M];
讀入
cin>>n>>e;
for(int i=1;i<=e;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
排序
sort(a+1,a+e+1,cmp);
就只有這么一行。
sort其實是algorithm頭文件的一個函數天通,用來排序泊窘,后面我會專門有一篇文章來講它 。
cmp是一個函數像寒,用來排序烘豹。
bool cmp(node x,node y){//注意開結構體類型
if(x.w<y.w)return 1;//如果邊 x的長度小于邊y的長度,函數返回真诺祸,也就是要交換的意思
if(x.w==y.w)//如果邊的長度相同(只是為了判重)
if(x.x>y.x)return 1;//返回 起點更大的
return 0;
}
主程序
for(int i=1;i<=e;i++)
{
if(getfather(a[i].x)!=getfather(a[i].y))
{//如果點 x與點y不在同一個集合里
ans+=a[i].w;//把這條邊 的長度加入總和
dad[getfather(a[i].x)]=a[i].y;//并 集過程
p++;//p記錄邊的數量
}
}//因為題目數據携悯,我就直接遍歷了所有邊
最后輸出
cout<<ans;//輸出總和
還是很簡單吧?
完整代碼:
#include <bits/stdc++.h>
using namespace std;
const int M=200100;
struct node{
int x;
int y;
int w;
}a[M];
int n,e,dad[M],p=1,ans;
bool cmp(node x,node y){
if(x.w<y.w)return 1;
if(x.w==y.w)
if(x.x>y.x)return 1;
return 0;
}
int getfather(int x){
if(x==dad[x])return x;
dad[x]=getfather(dad[x]);
return dad[x];
}
int main()
{
cin>>n>>e;
for(int i=1;i<=e;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
sort(a+1,a+e+1,cmp);
for(int i=1;i<=n;i++)dad[i]=i;
for(int i=1;i<=e;i++){
if(getfather(a[i].x)!=getfather(a[i].y)){
ans+=a[i].w;
dad[getfather(a[i].x)]=a[i].y;
p++;
}
}
cout<<ans;
return 0;
}