算法要点:Kruskal算法的最难点在于怎样判断加入边(x,y)后是否形成了环。
问题可化为:判断边(x,y)的两个顶点x,y在图(实际是森林)mst中最否已经连通。如果已经连通,加入边将形成环;否则,不形成环。
在kruskal算法中,要用到并查集的合并和查找
并查集:
1 int getfa(int k) //找到最祖先 2 { 3 if(fa[k]==k) return k; 4 fa[k]=getfa(fa[k]); 5 return fa[k]; 6 } 7 8 void merge(int x,int y) //合并祖先 9 { 10 int fx=getfa(x); 11 int fy=getfa(y); 12 fa[fx]=fy; 13 } 14 15 bool judge(int x, int y) //判断是不是一个祖先 16 { 17 int fx=getfa(x); 18 int fy=getfa(y); 19 return fx==fy; 20 }
kruskal算法核心:
1 for(int i=1;i<=n;i++) 2 fa[i]=i; 3 sort(e+1,e+1+len,mys); 4 int cal=0; 5 for(int i=1;i<=len;i++) 6 { 7 int v=getfa(e[i].x); 8 int u=getfa(e[i].y); 9 if(v!=u) 10 { 11 merge(v,u); 12 //根据题意添加 13 if(++cal==n-1) 14 { 15 break; 16 } 17 } 18 }
输入:
1 int fa[maxn]; 2 int len=0; 3 struct node 4 { 5 int x,y,v; 6 }e[maxn]; 7 8 void init(int xx,int yy,int vv) 9 { 10 if(yy<0||yy>n*m) return; 11 e[++len].y=yy; 12 e[len].x=xx;e[len].v=vv; 13 } 14 15 int main() 16 { 17 memset(e,0,sizeof(e)); 18 cin>>n>>m; 19 for(int i=1;i<=m;i++) 20 { 21 int xx,yy,vv; 22 cin>>xx>>yy>>vv; 23 init(xx,yy,vv); 24 init(yy,xx,vv); 25 }