P1546 [USACO3.1]最短网络 Agri-Net(洛谷)
很明显,这个题用邻接矩阵+dfs就能出(从不同点出发搜,且搜的时候更新最小值,可以剪枝,并且不成环) 。但算法标签中有并查集,因此此题尝试用并查集的方法来解决类似的连通图问题。
核心算法:
把每一条边按权值从小到大排序,然后依次看,如果两个端点不在一个集合里,就把他们合并,累加路径长度。如果已经包含所有点了,直接输出数据退出。(其实这也恰好是Kruskal算法的思想),在这里通过并查集来实现。
实现代码:
#include<bits/stdc++.h> using namespace std; int par[100]; int rank[100]; int n; int len[101][101]; int ans=0; //储存总路长 int remain=0; void init(){ for(int i=1;i<=n;i++){ par[i]=i; rank[i]=0; //高度最初为0 } } int find(int x){ if(par[x]==x){ return x; }else return par[x]=find(par[x]); } void unite(int x,int y){ x=find(x); y=find(y); if(x==y) return; if(rank[x]<rank[y]){ par[x]=y; }else{ par[y]=x; if(rank[x]==rank[y]){ rank[x]++; //高度加1 } } } bool same(int x,int y){ return find(x)==find(y); } typedef struct node{ int length; //保存长度 int a; int b; //保存两个端点 }T; T s[10000]; bool cmp(T k1,T k2){ //增序 return k1.length<k2.length; } int main(){ cin>>n; remain=n-1; init(); int t=0; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cin>>len[i][j]; if(i>j){ s[t].length=len[i][j]; //储存长度 s[t].a=i; //储存端点 s[t++].b=j; } } } sort(s,s+t,cmp); //边进行排序 for(int i=0;i<t;i++){ if(remain==0) break; //网络建完 if(same(s[i].a,s[i].b)) continue; if(!same(s[i].a,s[i].b)){ ans+=s[i].length; unite(s[i].a,s[i].b); //进行合并 remain--; } } cout<<ans; return 0; }