题意:给出n个节点的图,求最大边减最小边尽量小的值的生成树
首先将边排序,然后枚举边的区间,判定在该区间内是否n个点连通,如果已经连通了,则构成一颗生成树,
则此时的苗条度是这个区间内最小的(和kruskal一样,如果在已经构成一颗树的基础上,再继续加入边,由于边都是排过序的,再加入的边一定会更大)
再维护一个最小值就好了
自己写的时候,枚举区间没有写对,然后判断1到n个点连通又写了一个for循环
后来看lrj的代码:发现是这样判断1到n是否连通的,每次枚举一个区间的时候,初始化cnt=n,当cnt=1时,说明已经加入了n-1条边,构成生成树了,那么此时已经连通
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath> 5 #include<stack> 6 #include<vector> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<algorithm> 11 #define mod=1e9+7; 12 using namespace std; 13 14 typedef long long LL; 15 const int INF = 0x7fffffff; 16 const int maxn=10005; 17 int p[maxn]; 18 19 struct edge{ 20 int v,u,w; 21 bool operator <(const edge& rhs) const{ 22 return w<rhs.w;} 23 }; 24 25 26 27 int find(int x){return p[x]==x? x:p[x]=find(p[x]);} 28 29 int main(){ 30 int n,m,i,j,ans; 31 while(scanf("%d %d",&n,&m)!=EOF&&n){ 32 vector<edge> e; 33 edge ee; 34 for(i=0;i<m;i++){ 35 scanf("%d %d %d",&ee.v,&ee.u,&ee.w); 36 e.push_back(ee); 37 } 38 39 sort(e.begin(),e.end()); 40 41 int l,r; 42 ans=INF; 43 for(l=0;l<m;l++){ 44 int cnt=n; 45 for(i=0;i<=n;i++) p[i]=i; 46 for(r=l;r<m;r++){ 47 int x=find(e[r].v); 48 int y=find(e[r].u); 49 if(x!=y) { 50 p[x]=y; 51 cnt--; 52 if(cnt==1) { 53 ans=min(ans,e[r].w-e[l].w); 54 break; 55 } 56 } 57 } 58 } 59 60 if(ans==INF) printf("-1 "); 61 else printf("%d ",ans); 62 } 63 return 0; 64 }
go---go---go--