博客 UVA 1395 Slim Span 图论
题目大意:给定一个图,求可以连通图的一组边中最大边减最小边最小的一个方案
把边按权值大小进行排序,从小到大枚举L,对于每个L,从小到大枚举R,所有点连通时不再枚举
关键函数:
int solve(){
sort(edge+1,edge+1+m,cmp);
int ans=INF;
for(int L=1;L<=m;L++){
for(int i=1;i<=n;i++)pre[i]=i;
int cnt=n;//点睛之笔
for(int R=L;R<=m;R++){
int xx=find(edge[R].u);
int yy=find(edge[R].v);
if(xx!=yy){
pre[xx]=yy;
if(--cnt==1){ans=min(ans,edge[R].d-edge[L].d);break}
//通过cnt的自减与并查集判断图是否已经连通
//对于n结点的图n-1次操作连通
}
}
}
if(ans==INF)ans=-1;
return ans;
}完整代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=105;
const int INF=1000000000;
int n,m;
int pre[maxn];
struct node{
int u,v,d;
}edge[(maxn*maxn)/2];
int cmp(node a,node b){
return a.d<b.d;
}
int find(int lin){
int i=lin;
while(pre[i]!=i)i=pre[i];
int k=lin,j;
while(k!=i){
j=pre[k];
pre[k]=i;
k=j;
}
return i;
}
int solve(){
int ans=INF;
sort(edge+1,edge+m+1,cmp);
for(int L=1;L<=m;L++){
for(int i=1;i<=n;i++)pre[i]=i;
int cnt=n;
for(int R=L;R<=m;R++){
int xx=find(edge[R].u),yy=find(edge[R].v);
if(xx!=yy){
pre[xx]=yy;
if(--cnt==1){
ans=min(ans,edge[R].d-edge[L].d);
//cout<<R<<" "<<L<<" "<<ans<<endl;
break;
}
}
}
}
if(ans==INF)ans=-1;
return ans;
}
int main(){
while(scanf("%d%d",&n,&m) ==2 &&n){
for(int i=1;i<=m;i++)scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].d);
printf("%d\n",solve());
}
return 0;
}

浙公网安备 33010602011771号