第十一章例题 B - UVa1395 Slim Span

/*
SE:wn------王宁
使用间接排序而不是结构体实现
UVa1395 Slim Span
*/
/*思路就是从权重最小的边向上枚举边集E中的元素
最大边和最小边的差值和单独一方的值没有关系,所以需要枚举。
生成树的方法就是Kruskal,因为你越早找到最大边,差值就越小*/
/*经验总结
1.你用间接排序可能能节省每次交换数据的时间——只用交换编号
(操作原理:比如e[2]代表第二小的边的编号,e[2]=9,那么我们访问这条边的
两个端点就要把e[2]本身给代进去)
但是用结构体会直观很多,出错可能会小一些
2.变量命名:我把边数命名为m,后来设定结束条件(生成树不是应该具有比总结点
数目少一的边数嘛)设成了m-1.结果会导致答案全是-1*/
#include<bits/stdc++.h>
using namespace std; 
const int maxn=5000+5;
int w[maxn],u[maxn],v[maxn],e[maxn];//e[i]存储的是边的序号,使用间接排序
int f[100+5];
int cmp(int a, int b) { return w[a]<w[b]; }
int find(int x){ return x==f[x]?f[x]:f[x]=find(f[x]); }
int ans;
int m,n;
int main()
{
  int i,j,cnt,tmp,st,ed;
  while(cin>>n>>m&&n){
    for(i=1;i<=m;i++) scanf("%d%d%d",&u[i],&v[i],&w[i]); 
    for(i=1;i<=m;i++) e[i]=i; 
    sort(e+1,e+1+m,cmp);
    ans=-1;
    for(i=1;i<=m;i++)
    { 
      cnt=0; st=w[e[i]];
      //还要注意每次遍历都要先把f给还原——每个点都是自己的代表元  
      for(j=1;j<=n;j++) f[j]=j; 
      for(j=i;j<=m;j++)
      {
        tmp=e[j]; int x=find(u[tmp]),y=find(v[tmp]);
        if(x!=y) {
          f[x]=y;
          ++cnt;
        }
        //错就错在应该是集齐了n-1条边就应该收手的,写成了m-1了 
        if(cnt==n-1) break;
      }
      if(j==m+1) continue;
      ed=w[e[j]];
      if(ans==-1) ans=ed-st;
      else ans=min(ans, ed-st);
    }
    cout<<ans<<endl;
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/JXUFE_ACMer/article/details/81663533