Description
因为一场不小的地震,Y 省n 个城市之间的道路都损坏掉了,省长希望小X 将城市之间的道路重修一遍。
很多城市之间的地基都被地震破坏导致不能修路了,因此可供修建的道路只有m 条。因为施工队伍有限,省长要求用尽量少的道路将所有的城市连通起来,这样施工量就可以尽量少。不过,省长为了表示自己的公正无私,要求在满足上述条件的情况下,选择一种方案,使得该方案中最贵道路的价格和最便宜道路的价格的差值尽量小,即使这样的方案会使总价提升很多也没关系。
小X 现在手忙脚乱,希望你帮帮他。
Solution
首先最小生成树上最大的边最小。
排序后从大到小加边,如果出现了环,那么当前的边可以代替环上最大的边,然后如果图中有n-1条边就统计答案。
那么树上动态加边,可以暴力做,范围不大。
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define rep(i,x) for(int i=ls[x];i;i=nx[i])
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 2010
#define M 30010
using namespace std;
struct node{
int u,v,w;
}e[M];
bool cmp(node x,node y){
return x.w<y.w;
}
int fr[M],to[M],nx[M],ls[N],val[M],ls1[M],num=0;
int zd,mx,c,n,o=0;
bool bz[M];
void link(int x,int y,int c)
{
num++;
fr[num]=x;
to[num]=y;
nx[num]=ls[x];
ls1[ls[x]]=num;
ls[x]=num;
val[num]=c;
}
bool jy;
void dfs(int x,int fa)
{
if(x==zd)
{
jy=true;
return;
}
rep(i,x)
if(!bz[i])
{
o++;
int v=to[i];
if(v!=fa)
{
int t1=mx,t2=c;
if(mx<val[i]) mx=val[i],c=i;
dfs(v,x);
if(jy) return;
mx=t1,c=t2;
}
}
}
int g(int x){
return x%2?(x+1):(x-1);
}
void find(int x,int fa)
{
rep(i,x)
if(!bz[i])
{
int v=to[i];
if(v!=fa)
{
if(mx<val[i]) mx=val[i];
find(v,x);
}
}
}
int main()
{
int m;
scanf("%d %d",&n,&m);
fo(i,1,m)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
e[i].u=u,e[i].v=v,e[i].w=w;
}
sort(e+1,e+m+1,cmp);
int t=0;
int ans=2147483647,gg=0;
fd(i,m,1)
{
zd=e[i].v;
int u=e[i].u,v=e[i].v,w=e[i].w;
mx=0;
o=0;
jy=false;
dfs(u,0);
if(jy)
{
t--;
if(!ls1[c]) ls[fr[c]]=nx[c];
else nx[ls1[c]]=nx[c];
if(nx[c]) ls1[nx[c]]=ls1[c];
c=g(c);
if(!ls1[c]) ls[fr[c]]=nx[c];
else nx[ls1[c]]=nx[c];
if(nx[c]) ls1[nx[c]]=ls1[c];
}
link(u,v,w);
link(v,u,w);
t++;
if(t==n-1)
{
mx=0;
find(u,0);
if(ans>mx-w) ans=mx-w;
}
}
if(ans==2147483647) printf("-1");
else printf("%d",ans);
}