3316 - 最小差值生成树

CodeWaySky很早就学了最小生成树,所以CodeWaySky现在对简单的求最小生成树不感兴趣了。现在CodeWaySky想知道,对于一个给定的图,它的所有生成树中,最大边和最小边的边权差最小是多少。
因为CodeWaySky这个技术人员实在太忙了,到处帮大家解决问题,无法脱身,所以这个问题就交给你来解决了。

题目输入

第一行,两个用空格隔开的整数 N 和 M,分别表示顶点数和边数。
下面 M 行,每行 3 个数 u,v,w,表示 u 和 v 之间有一条权值为 w 的无向边。

题目输出

一行,一个非负整数,表示最大边和最小边的最小边权差。
若图本身不连通,则输出-1

输入/输出样例

题目输入

4 5 
1 2 3 
1 3 5 
1 4 6 
2 4 6 
3 4 7

题目输出

1

提示

【数据范围】
20%    M<=200
100%     2<=N<=100, 0<=M<=5000

C++解答

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <fstream>
#include <algorithm>
#include <map>
using namespace std;
int N,M;
int my_max=0;
int my_min=0x7fffffff;
struct NODE{
	int x,y;
	int va;
}a[5005];
int ff[105],r1,r2;
int f[105];
bool exist[10005];
int find(int x){
//	cout<<x<<endl;
	if(x!=f[x])f[x]=find(f[x]);
	return f[x];
}
int ffind(int x){
	if(ff[x]!=x)ff[x]=ffind(ff[x]);
	return ff[x];
}
bool tepan(){
	for(int i=1;i<=N;i++)ff[i]=i;
	for(int i=1;i<=M;i++){
		r1=ffind(a[i].x);
		r2=ffind(a[i].y);
		if(r1!=r2){
			if(r1>r2)swap(r1,r2);
			ff[r2]=r1;
		}
	}
	for(int i=1;i<=N;i++)if(ffind(i)==i&&i!=1)return true;
	return false;
}
int comp(const NODE &X,const NODE &Y){
	return X.va<Y.va;
}
bool bing(int s1,int s2){
	for(int i=s1;i<=s2;i++){
		r1=find(a[i].x);
		r2=find(a[i].y);
		if(r1!=r2){
			if(r1>r2)swap(r1,r2);
			f[r2]=r1;
		}
	}
	for(int i=1;i<=N;i++)if(find(i)==i&&i!=1)return false;
	return true;
} 
bool judge(int x){
	int stj,t,j;
	memset(exist,0,sizeof(exist));
	for(int i=1;i<=M;i++){
		while(exist[a[i].va]==true)i++;
		t=a[i].va;//bool标记用过次边权 
		exist[a[i].va]=true;
		j=i+1;
		while(a[j].va-a[i].va<=x){
			j++;
			if(j>M)break;
		}
		for(int v=1;v<=N;v++)f[v]=v; 
		if(bing(i,j-1))return false;//如果此区间内的边并起来满足的话,差值大了 
	}
	return true;//怎么并都不行 
}
void work(){
	int l=0;
	int r=my_max-my_min;
	int mid=(l+r)/2;
	while(l<=r){
		mid=(l+r)/2;
		if(judge(mid))l=mid+1;
		else r=mid-1;
	}
	cout<<l<<endl;
}
int main(){
//	freopen("1.in","r",stdin);
	//freopen("span.in","r",stdin);
	//freopen("span.out","w",stdout);
	scanf("%d%d",&N,&M);
	for(int i=1;i<=M;i++){
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].va);
		my_max=my_max>a[i].va? my_max:a[i].va;
		my_min=my_min<a[i].va? my_min:a[i].va;
	}
	if(tepan()){
		cout<<-1<<endl;
		return 0;
	}
	sort(a+1,a+M+1,comp);
	work();
	fclose(stdin);
	fclose(stdout);
	return 0;
}

提示

【数据范围】
20%    M<=200
100%     2<=N<=100, 0<=M<=5000

时间限制 1 秒
内存限制 128 MB
讨论 统计
上一题 下一题