\(By:Soroak\)算法
定義: \(Kruskal\) 是基於貪心的思想獲得的。
首先咱們把全部的邊按照權值先從小到大排列,接着按照順序選取每條邊,若是這條邊的兩個端點不屬於同一集合,那麼就將它們合併,直到全部的點都屬於同一個集合爲止。看到這裏,咱們不難想到另一個算法——並查集,說白了, \(Kruskal\) 算法就是基於並查集的貪心算法。函數
基本思想: \(Kruskal\) 是以邊爲主導地位,始終選擇當前可用的最小邊權的邊,每次選擇邊權最小的邊鏈接的時候,要判斷兩個端點之間有沒有聯通。spa
代碼以下:(感謝gyh大佬的「贊助」)code
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; struct edge { int u,v,w;//分存每一條邊前,後坐標與權值 }a[3000010]; int n,m,num;//存邊的數量 int pre[1000010];//存並查集中的祖先 bool cmp(edge aa,edge bb) { return aa.w<bb.w; }//結構體sort排序必須自定義排序函數 void add(int u,int v,int w) { a[++num].u=u; a[num].v=v; a[num].w=w; } int find(int x) { return pre[x]==x?x:pre[x]=find(pre[x]); } void join(int x,int y)//並集 { int r1=find(x),r2=find(y); if(r1!=r2) { pre[r1]=r2; } } signed main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { pre[i]=i;//重置先祖 } for(int j=1;j<=m;j++) { int u,v,w; scanf("%d%d%d",&u,&v,&w);//輸入各邊權值 add(u,v,w); } sort(a+1,a+num+1,cmp); int sum=0; for(int i=1,tot=0;i<=num&&tot!=n;i++) { if(find(a[i].u)==find(a[i].v)) { continue; } join(a[i].u,a[i].v); ++tot; sum+=a[i].w; } printf("%d",sum);//輸出 return 0; }
代碼:blog
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> const int INF = 0x7ffff;//最大值 const int MARX = 1e5+10; using namespace std; //============================================================= struct edge { int u,v,w,ne;//分存前點 後點 權重 }e[MARX<<2]; struct p { int num,diss; bool operator < (const p &a) const { return diss > a.diss; } }tmp; int head[MARX],dis[MARX]; bool f[MARX]; int num,n,m,s=1; //============================================================= void add(int u,int v,int w)//鄰接表加入元素 { e[++num].ne=head[u],head[u]=num; e[num].u=u,e[num].v=v,e[num].w=w; } void dj(int s) { priority_queue <p> q; tmp.num=s,tmp.diss=0;q.push(tmp); for(int i=1;i<=n;i++) dis[i]=INF;//賦極值 dis[s]=0;//初始化 for(int i=0;i<n && (!q.empty());) { int top=q.top().num; q.pop(); if(f[top]) continue; i++,f[top]=1; for(int j=head[top];j;j=e[j].ne)//找k點的臨點,並進行比較 if(dis[e[j].v] > e[j].w && (!f[e[j].v])) { dis[e[j].v] = e[j].w; tmp.num=e[j].v , tmp.diss=dis[e[j].v]; q.push(tmp); } } } //============================================================= int main() { scanf("%d%d",&n,&m);//輸入 for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } dj(s); int sum=0; for(int i=1;i<=n;i++) sum+=dis[i]; printf("%d",sum); } /* //如題,此題爲最小生成樹prim模板 //再也不贅述 #include<cstdio> #include<algorithm> using namespace std; const int MARX=2147483646; struct baka9 { int u,v,w,ne; }a[401000]; int head[20010]; int minn[20010]; bool f[20010]; int n,m,ans,num; void add(int x,int y,int z) { a[++num].ne=head[x]; a[num].u=x; a[num].v=y; a[num].w=z; head[x]=num; } bool prim(); int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } if( prim() ) printf("%d",ans); else printf("orz"); } bool prim() { for(int i=2;i<=n;i++) minn[i]=MARX; for(int i=head[1];i;i=a[i].ne) minn[a[i].v]=min(minn[a[i].v],a[i].w); for(int i=1;i<n;i++) { int minnn=MARX,k=-1; for(int j=1;j<=n;j++) if(!f[j] && minn[j]<minnn) { minnn=minn[j]; k=j; } if(k==-1) break; f[k]=1; for(int l=head[k];l;l=a[l].ne) { if(!f[a[l].v] && minn[a[l].v] > a[l].w) minn[a[l].v]=a[l].w; } } for(int i=1;i<=n;i++) { if(minn[i]==MARX) return 0; ans+=minn[i]; } return 1; } */