算法要點: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 }