給出一個\(n(n<=100)\)個節點的的圖,求最大邊減最小邊儘可能小的生成樹。c++
\(Kruskal\)算法
首先把邊按邊權從小到大進行排序。對於一個連續的邊集區間\([L,R]\),若是這些邊使得\(n\)個點所有聯通,則必定存在一個苗條度不超過\(W[R]-W[L]\)的生成樹(其中\(W[i]\)表示排序後第\(i\)條邊的權值)。spa
從小到大枚舉\(L\),對於每一個\(L\),從小到大枚舉\(R\),同時用並查集將新進入\([L,R]\)的邊兩端的點合併成一個集合,與\(Kruskal\)算法同樣。當全部的點都聯通是中止枚舉\(R\),換下一個\(L\)(而且把\(R\)重置爲\(L\)),繼續枚舉。code
#include<bits/stdc++.h> using namespace std; const int MAXN=100+10; const int MAXM=10000+10; int n,m; int fa[MAXN]; int maxn,ans=0x3f3f3f3f; struct Node { int u,v,w; }edge[MAXM]; inline int read() { int tot=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') { tot=tot*10+c-'0'; c=getchar(); } return tot; } inline bool cmp(Node x,Node y) { return x.w<y.w; } inline int find(int k)//並查集 { if(fa[k]==k)return k; else return fa[k]=find(fa[k]); } inline bool kruskal(int k)//判斷是否能造成生成樹 { maxn=0; int tot=0; for(int i=1;i<=n;i++) fa[i]=i; for(int i=k;i<=m;i++) { if(fa[find(edge[i].u)]!=fa[find(edge[i].v)]) { maxn=edge[i].w; fa[find(edge[i].u)]=fa[find(edge[i].v)]; tot++; } if(tot==n-1)return 1;//若是全部點都聯通,則返回true } return 0;//不然返回false } int main() { while(1) { ans=0x3f3f3f3f; n=read();m=read(); if(!n&&!m)break; for(int i=1;i<=m;i++) { edge[i].u=read(); edge[i].v=read(); edge[i].w=read(); } sort(edge+1,edge+1+m,cmp);//給邊進行從小到大排序 for(int i=1;i<=m;i++)//枚舉L { if(kruskal(i)) { ans=min(ans,maxn-edge[i].w);//更新最小值 } } if(ans!=0x3f3f3f3f)cout<<ans<<endl; else cout<<-1<<endl;//特判 } return 0; }
劉汝佳大法好!排序