最小差异值 图论+贪心
【问题描述】
P 省刚经历一场不小的地震,所有城市之间的道路都损坏掉了,所以省长想
请你将城市之间的道路重修一遍。
因为很多城市之间的地基都被地震破坏导致不能修公路了,所以省长给定了
你一些城市对,在这些城市对之间可以修公路,并且都有相应的价格。而且因为
施工队伍有限,所以省长要求用尽量少的道路将所有的城市连通起来,这样施工
量就可以尽量少,道路可视为无向边,且数据保证至少有一种连通的方案。不过,
省长为了表示自己的公正无私,要求在满足上述条件的情况下,选择一种方案,
使得该方案中最贵道路的价格和最便宜道路的价格的差值尽量小,即使这样的方
案会使总价提升很多也没关系。
那么,请你尽快地安排一种合理的方案,满足省长的要求。
【输入格式】
第一行两个数 N,M,表示城市的个数以及可以修的公路数;
第二行开始 M 行,每行三个数 a,b,c,表示 a,b 之间可以修一条价值 c 的无向
道路。
【输出格式】
一个数表示该方案中最大边减去最小边的值,要求要尽量的小。
【样例输入】
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
【样例输出】
1686
【样例说明】
选第 4,5,6,9 条边即可。
【数据说明】
30%数据满足 N<=M<=20
100%数据满足 N<=M<=5000,0<c<=50000;
相信大家看到这题,最先想到的肯定是最小生成树。但是最小生成树是求总路径最小的,而这题明确说了不考虑总长度,所以我们需要考虑怎么转换我们平时学的最小生成树。
首先,要求差值最小,那一定就和大小有关,那我们先把边拿出来排一遍序。
然后我们枚举最小边,不断往大加边,每加一条边就判断是否满足最小生成树,满足就和最小差值比较,然后枚举下一条小边(很明显)。
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define ll long long #define il inline #define db double using namespace std; il int gi() { int x=0,y=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') y=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*y; } il ll gl() { ll x=0,y=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') y=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*y; } struct edge { int a,b; ll dis; }e[5045]; bool cmp(edge x,edge y) { return x.dis<y.dis; } int fa[5045]; int find(int x) { if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } int n,m,x,y,z,now; il bool hzr(int x,int y) { for(int i=1;i<=n;i++) fa[i]=i; for(int i=x;i<=y;i++) { int r1=find(e[i].a),r2=find(e[i].b); if(r1!=r2) { now++; fa[r2]=r1; } } } int main() { freopen("dvalue.in","r",stdin); freopen("dvalue.out","w",stdout); n=gi(),m=gi(); for(int i=1;i<=m;i++) { x=gi(),y=gi(),z=gl(); e[i].a=x; e[i].b=y; e[i].dis=z; } sort(e+1,e+1+m,cmp); ll minx=1e16; for(int i=1;i<=m-n+2;i++) { now=0; hzr(i,i+n-2); if(now==n-1) { if(e[i+n-2].dis-e[i].dis<minx) minx=e[i+n-2].dis-e[i].dis; continue; } for(int j=i+n-1;j<=m;j++) { int r1=find(e[j].a),r2=find(e[j].b); if(r1!=r2) { now++; fa[r2]=r1; } if(now==n-1) { if(e[j].dis-e[i].dis<minx) minx=e[j].dis-e[i].dis; break; } } } printf("%lld\n",minx); return 0; }