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
题目分析
1.题意
本题就是说让我们找一条路径从P到Q,是这条路上的最大速度限制与最小速度限制相差最小。
同样要运用到并查集。
2.分析
很明显我们要使最大速度限制尽可能的小,而最小速度限制尽可能的大。
那么我们每次在枚举的过程:
1.将题中给出的数据进行合并;
2.总是需要判断P,Q两点是否相连(即在并查集中,两者根一致),而且我们在路径压缩的同时也能够知道,两者的“父亲”也肯定是一样的。
3.最后退出循环,判断两者父亲节点是否相同,更新答案。
PS:注意排序!!!
代码:
#include <cstdio>
#include <climits>
#include <algorithm>
#pragma GCC optimize(2)
using namespace std;
int n,m,k;
int fa[201];
struct way
{
int x,y,v; //x:出发点,y:目的点,v:速度
} s[1001];
int find(int x)
{
return x==fa[x]? x:fa[x]=find(fa[x]);
//路径压缩,将路上递归到的父亲节点指针顺带指向根节点
//三目运算符更加简便
}
int solve(int P,int Q)
{
int i,l,ans=INT_MAX;
//注意循环里的数要定义在外,否则在判断时,循环变量只在循环里起作用
//ans初始化
for (i=1;i<=m;i++) //枚举最小速度
{
for (int j=1;j<=n;j++) fa[j]=j; //初始化
for (l=i;l<=m;l++) //保证枚举到的最大速度一定不小于最小速度
//所以需要sort,便于循环枚举
{
int a=find(s[l].x),b=find(s[l].y); //取出两个点的根
if (a!=b) fa[b]=a; //如若不在同一连通块,合并
if (find(P)==find(Q)) break; //若P与Q在同一连通块,则退出
}
if (fa[P]==fa[Q]&&ans>s[l].v-s[i].v)
//因为已经路径压缩,那么P和Q点的父亲一定为同一节点
//同时注意,如果P和Q并没有相连,循环也会退出,所以需要判断
//ans大于现所算出的答案才更新
ans=s[l].v-s[i].v; //更新ans
}
return ans;
}
bool cmp(way a,way b)
{
return a.v<b.v; //按速度大小排序
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].v);
sort(s+1,s+m+1,cmp);
//排序,注意按速度排序,后面会讲到
int p,q;
scanf("%d",&k);
for (int i=0;i<k;i++)
{
scanf("%d%d",&p,&q);
printf("%d\n",solve(p,q));
}
return 0;
}