\(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; } */