pku 3522 Kruskal+枚举 灵活应用

题目连接:http://acm.pku.edu.cn/JudgeOnline/problem?id=3522

题目大意:求一颗生成树使得树边的最大值与最小值之差最小。。

算法分析:

              1,对边进行从小到大的排序。。

              2,设在[i,m-1]条边中求一颗生成树,Minant=min(Minant,Max-Min),那么枚举权值最小边i,如果[i,m-1]中找不到生成树的话,后面的[i+1,m-1]......都没有生成树了。。

              3,Kruskal算法的并查集实现;

#include<iostream> #include<stdio.h> #include<algorithm> using namespace std; const int inf=99999999; const int MAXM=5000; const int MAXN=200; struct node { int v1,v2; int weight; }E[MAXM]; int p[MAXN],rank[MAXN]; int n,m,Minant; int cmp(node a,node b) { return a.weight<b.weight; } void MakeSet() { for(int i=0;i<=n;i++) { p[i]=i; rank[i]=0; } } int FindSet(int x) { if(p[x]!=x) p[x]=FindSet(p[x]); return p[x]; } void UnionSet(int x,int y) { if(rank[x]>rank[y]) p[y]=x; else { p[x]=y; if(rank[x]==rank[y]) rank[x]++; } } bool Kruskal(int i) { MakeSet(); int Numedge=0,Min=inf,Max=-inf; for(int j=i;j<m;j++) { if(Numedge==n-1) break; int fx=FindSet(E[j].v1),fy=FindSet(E[j].v2); if(fx!=fy) { Numedge++; if(E[j].weight<Min) Min=E[j].weight; if(E[j].weight>Max) Max=E[j].weight; UnionSet(fx,fy); } } if(Numedge==n-1) { Minant=min(Minant,Max-Min); return true; } else return false; } int main() { while(scanf("%d%d",&n,&m)&&(n+m)) { Minant=inf; for(int i=0;i<m;i++) scanf("%d %d %d",&E[i].v1,&E[i].v2,&E[i].weight); sort(E,E+m,cmp); for(int i=0;i<m;i++) { bool more=Kruskal(i); if(more==false) break; } if(Minant==inf) printf("-1/n"); else printf("%d/n",Minant); } return 0; }

 

你可能感兴趣的:(算法,struct)