http://acm.hdu.edu.cn/showproblem.php?pid=1598
主要是用到了并查集和枚举,通过枚举来表示不同的连通状态。
题解: 用贪心的策咯将所有的路按照速度从小到大的顺序存储,然后在枚举每一个路 road1与它后边比它速度大的所有路road2,用并查集判断所求的两个点是否联通,如果两个点连通,那么最大值就是现在枚举到的点road2,最小值就是前面road1,如果此时的road2 - road1 更小,更新min = road2 - road1,一直枚举完所有的路;
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 1e5+5;
int n,m;
int inf = INT_MAX;
int acount[maxn][20];
int amount[maxn];
int pre[maxn]; //并查集
struct edge{
int s,e,speed;
edge(int a,int b,int c){
s = a,e = b, speed = c;
}
friend bool operator<(const edge&e1,const edge&e2){
return e1.speed < e2.speed; //sort按照速度从小到大排序
}
};
int find(int x){
return x ==pre[x] ? x : pre[x]=find(pre[x]); //并查集找父节点
}
int main(){
int ans = 0;
while(scanf("%d%d",&n,&m)!= EOF){
vector<edge>edges;
for(int i = 1; i<= m;i++){
int s,e,speed;
cin>>s>>e>>speed;
edges.push_back(edge(s,e,speed)); //初始化
}
sort(edges.begin(),edges.end()); //将所有的路按照从小到大的顺序存储
int start,end;
int q;
cin>>q;
amount[ans]=q;
for(int k =0; k < q; k++){
cin>>start>>end; //所求两点
int mi = inf;
for(int i = 0; i < edges.size();i++){ //枚举 所有的路
for(int i2 = 0; i2<= n ;i2++)
pre[i2]=i2;
for(int j = i; j < edges.size();j++){ //枚举从i以后所有的路
int fs = find(edges[j].s); //从i以后的所有路都要加入并查集中
int fe = find(edges[j].e);
if(fs != fe)
pre[fs]=fe;
if(find(start)==find(end)){ //如果此时start 和 end 恰好连通 我们就可以开始更新mi
mi = min(mi,edges[j].speed-edges[i].speed); // 因为i是枚举作为第一条路所以最小值是edge[i].speed 而 edge[j].speed 是当前最后枚举的 所以它为最大值
}
}
}if(mi == inf) acount[ans][k] = -1;else
acount[ans][k]=mi;
}
ans++;
}
for(int i = 0; i < ans ;i++)
for(int j =0; j < amount[i];j++)
cout<<acount[i][j]<<endl;
return 0;
}