Problem : 暴力摩托
原文
Time Limit: 1 Sec Memory Limit: 128 MB
Description
N个站,之间连了M条双向的通路!但每条路都规定了一个速度的限制值,在这条路上必须以这个速度前进!所以在
前进的时候要调整速度,现决定尽量使调整的幅度小一些,也就是使走过的路的速度最大值与最小值之差最小!
Input
第一行有2个正整数N , M , 分别表示站点数,路径数.
接下来M行,每行有3个正整数 X, Y, V表示X, Y之间有一条路,其Speed值是V。
再接下来是数K, 表示任务数,
下面K行,每行有一对正整数P,Q ,表示一个任务从P到Q.
(1<=n<=200, 1<=m<=1000, 1<=K<=10)
Output
对于每一个任务输出一行,仅一个数,即最大速度与最小速度之差。
Sample Input
4 4
1 2 2
2 3 4
1 4 1
3 4 2
2
1 3
1 2
Sample Output
1
0
HINT
相信有很多人和吴伊茗一样,在看到这道题的时候最先想到的就是树或是dfs,但再看看数据范围,能不能过自己心里也没底,最后看看标签 “并查集” ,顿时摸不着头脑,接着就放弃了。
其实,这题也没有这么难,我们可以用并查集来优化。
由于要使两者差最小,则必须使最大值尽可能的小,使最小值尽可能的大。
步骤:
1、我们先按每一条边的值从小到大排序(至于为什么,后面会讲到)
2、接着,我们可以枚举最最小权值的边,在以这条边为起点,去搜索能使x和y两点相连的路线(这里需要运用并查集,若两者的根相同,则可以相连),找到一条能使x和y相连的最大权值的边,就跳出循环(由于之前已经排好序,所以在它后面的,肯定会比当前值大),继续枚举。
3、若能够相连,则以当前值的差与小差去作比较,取较小值。
4、一次打印一个即可。
code:
#include<bits/stdc++.h>
using namespace std;
int f[201],x,y,n,m;
struct dd {
int x,y,z;//x、y为这条边的两个结点,z为权值
} v[1001];
bool cmp(dd a,dd b) {
return a.z<b.z;
}
int find(int i) {
if(f[i]==i) return i;
return f[i]=find(f[i]);//并查集,扁平化使时间缩短
}
void work() {
int i,j,ans=INT_MAX;
for(i=1; i<=m; i++) {//枚举最小值
for(j=1; j<=n; j++) f[j]=j;//初始化
for(j=i; j<=m; j++) {//枚举最大值,保证最大值比最小值大
if(find(v[j].x)!=find(v[j].y))//若当前边还未相连,则把两点相连
f[find(v[j].x)]=find(v[j].y);
if(find(x)==find(y))//若找到路线,则退出循环
break;
}
if(f[x]==f[y])//若以当前值为最小值,且x与y能够相连,则去作比较
ans=min(ans,v[j].z-v[i].z);//最大值减去最小值
}
printf("%d
",ans);
}
int main() {
int i,j,k;
scanf("%d%d",&n,&m);
for(i=1; i<=m; i++) scanf("%d%d%d",&v[i].x,&v[i].y,&v[i].z);
sort(v+1,v+m+1,cmp);//排序
scanf("%d",&k);
for(i=1; i<=k; i++) {
scanf("%d%d",&x,&y);
work();
}
}