博客 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;
}

posted @ 2018-05-06 09:53  琳小羽  阅读(111)  评论(0)    收藏  举报