poj 3522(求最小生成树,使得最边和最小边差最小)

88 篇文章 0 订阅

    枚举最小边,用kruskal求生成树,不断更新最小值就可以了。
 给定一个简单图,n个点,m条边( 1<=n<=100,0 ≤ m ≤ n(n − 1)/2 ),要求一颗生成树,使得其最大边与最小边的差值是所有生成树中最小的,输出最小的那个差值。
分析:
  类似于kruskal算法求最小生成树,将所有边按权值大小排升序,e1,e2,e3,...em。
  枚举每条边ei,对ei,ei+1,ei+2,ei+3...进行求生成树,不断更新差值得到最优值。
 #include <cstdio>
 #include <cstring>
 #include <cmath>
 #include <iostream>
 #include <algorithm>
 #include <vector>
 using namespace std;
 
 #define mpair make_pair
 #define pii pair<int,int>
 #define MM(a,b) memset(a,b,sizeof(a));
 typedef long long lld;
 typedef unsigned long long u64;
 template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
 template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}
 #define maxn
 
 int n,m;
 struct Edge{
     int u,v,w;
     void read(){
         scanf("%d%d%d", &u, &v, &w);
     }
     bool operator<(Edge b)const{
         return w<b.w;
     }
 } edge[10050];
 
 const int inf= 200000000;
 int fa[110];
 int find(int x){
     if( x==fa[x] ) return x;
     else return fa[x]= find( fa[x] );
 }
 int solve(){
     int ans= inf;
     for(int k=1;k<=m;++k){
         for(int i=1;i<=n;++i) fa[i]= i;
         int mmin= inf, mmax= -inf;
         int cnt= 0;
 
         for(int i=k;i<=m;++i){
             int x= edge[i].u, y= edge[i].v;
             int fx= find(x), fy= find(y);
             if( fx!=fy ){
                 fa[fy]= fx;
                 up_min( mmin, edge[i].w );
                 up_max( mmax, edge[i].w );
                 if( ++cnt == n-1 ) break;
                 if( mmax-mmin >= ans ) break; ///
             }
         }
         if( cnt == n-1 ) up_min( ans, mmax-mmin );
     }
     return ans;
 }
 
 int main()
 {
     while( cin>>n>>m, (n+m) ){
         for(int i=1;i<=m;++i)
             edge[i].read();
         sort( edge+1, edge+1+m );
 
         int ans= solve();
         if( ans!=inf ) cout<< ans <<endl;
         else puts("-1");
     }
 }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值