Description
因为一场不小的地震,Y 省n 个城市之间的道路都损坏掉了,省长希望小X 将城市之间的道路重修一遍。
很多城市之间的地基都被地震破坏导致不能修路了,因此可供修建的道路只有m 条。因为施工队伍有限,省长要求用尽量少的道路将所有的城市连通起来,这样施工量就可以尽量少。不过,省长为了表示自己的公正无私,要求在满足上述条件的情况下,选择一种方案,使得该方案中最贵道路的价格和最便宜道路的价格的差值尽量小,即使这样的方案会使总价提升很多也没关系。
小X 现在手忙脚乱,希望你帮帮他。
Input
第一行包含两个整数n;m。
接下来m 行,每行包含三个整数a; b; c,表示城市a; b 之间可以修建一条价格为c 的无向道路。
Output
若存在合法方案,则第一行包含一个整数,表示最贵道路的价格和最便宜道路的价格的最小差值;
否则第一行包含一个整数−1。
Sample Input
输入1: 5 10 1 2 9384 1 3 887 1 4 2778 1 5 6916 2 3 7794 2 4 8336 2 5 5387 3 4 493 3 5 6650 4 5 1422 输入2: 2 0
Sample Output
输出1: 1686 输出2: -1
Data Constraint
• 对于30% 的数据,n;m ≤ 20。
• 对于60% 的数据,n ≤ 1000,m ≤ 4000。
• 对于100% 的数据,2 ≤ n ≤ 2000,0 ≤ m ≤ 15000,a ̸= b,1 ≤ c ≤ 2 × 10^9。
Solution
对于60pts,枚举最小边,从这里开始做最小生成树,由于最小生成树最大边最小,可以保证是最优答案。
对于100pts,我们发现我们每次都做了一遍最小生成树,其实没有必要,我们从大到小枚举最小的边后,我们需要做的世纪上是在没加入一条边后,维护出当前图的最小生成树,那么当加入一条边时,我们考虑它是否与之前的边构成环,如果构成环,就将环上最大边删去,用当前这条较小边代替一定更优,如果不构成环,就直接加入边中。找环中最大边可以用 DFS 实现。 若图中现有的边数为 n − 1,我们就可以更新答案。 时间复杂度 O(m log m + mn),期望得分 100 分。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define I int
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define N 15010
using namespace std;
void rd(I &x){
x=0;I w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
x*=w;
}
I n,m,cnt,tot,f[2010],st[2010],fa[2010],E[2010],ls[N],nx[N*2],t[N*2],id[N*2],ans=2147483647;
struct node{I x,y,z;}a[N];
I cmp(node x,node y){return x.z>y.z;}
I get(I x){return f[x]==x?x:f[x]=get(f[x]);}
void add(I x,I y,I z){t[++tot]=y,nx[tot]=ls[x],ls[x]=tot;id[tot]=z;}
void dg(I x,I y,I op){
fa[x]=y;st[x]=op;
for(I k=ls[x];k;k=nx[k]) if(t[k]!=y){dg(t[k],x,id[k]);}
}
I work(I l,I r){
cnt=0;
F(i,1,n) f[i]=i;
F(i,l,r){
I fx=get(a[i].x),fy=get(a[i].y);
if(fx!=fy) {f[fx]=fy,cnt++;}
if(cnt==n-1) return 1;
}
return 0;
}
I main(){
freopen("construction.in","r",stdin);
freopen("construction.out","w",stdout);
rd(n),rd(m);
F(i,1,m){rd(a[i].x),rd(a[i].y),rd(a[i].z);}
sort(a+1,a+1+m,cmp);
if(!work(1,m)){
printf("-1\n");
return 0;
}
cnt=0;
F(i,1,n) f[i]=i;
F(i,1,m){
I fx=get(a[i].x),fy=get(a[i].y);
if(fx!=fy){
f[fx]=fy,cnt++;
E[++E[0]]=i;
}
else{
tot=0;
mem(ls,0);
mem(fa,0);
F(j,1,E[0]){
add(a[E[j]].x,a[E[j]].y,j);
add(a[E[j]].y,a[E[j]].x,j);
}
dg(a[i].x,0,0);
I x=a[i].y,ma=0,mk=0;
while(x!=a[i].x){
if(a[E[st[x]]].z>ma){
ma=a[E[st[x]]].z;
mk=st[x];
}
x=fa[x];
}
E[mk]=i;
}
if(cnt==n-1){
I ma=0;
F(j,1,E[0]) ma=max(ma,a[E[j]].z);
ans=min(ans,ma-a[i].z);
}
}
printf("%d\n",ans);
return 0;
}