题意:求从s到t的所有路线中最大边权与最小边权差值的最小值。
方法一:并查集+贪心
将边按照边权从小到大排序,然后依次选取边作为从s到t路线的最小边,然后再按照边权从小到大不断加边,直到s、t联通,则最后加的边的边权与最小边权的差是答案的一个可能解。对最小边依次枚举,答案为所有可能解的最小值。
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn = 205;
const int maxm = 1005;
const int inf = 0x3f3f3f3f;
int n,m;
struct edge{
int u,v,speed;
bool operator < (const edge& z){
return speed < z.speed;
}
}e[maxm];
int len;
int par[maxn];
void init_union(){CLR(par,-1);}
int find(int x){while(par[x]>=0) x=par[x]; return x;}
void unite(int x,int y){x=find(x);y=find(y);if(x!=y)par[y]=x;}
bool same(int x,int y) { return find(x) == find(y);}
void solve(int s,int t){
int ans = inf;
for(int i=0;i<len;i++){
init_union();
bool flag = false;
for(int j=i;j<len;j++){
unite(e[j].u,e[j].v);
if(same(s,t)){
flag = true;
ans = min(ans,e[j].speed-e[i].speed);
break;
}
}
if(!flag) break;
}
if(ans == inf) printf("-1\n");
else printf("%d\n",ans);
}
int main(){
while(~scanf("%d%d",&n,&m)){
len = 0;
int a,b,c;
while(m--){
scanf("%d%d%d",&a,&b,&c);
e[len].u = a;
e[len].v = b;
e[len].speed = c;
len++;
}
sort(e,e+len);
int q;
scanf("%d",&q);
while(q--){
int s,t;
scanf("%d%d",&s,&t);
solve(s,t);
}
}
return 0;
}
方法二:二分+DFS
【copy】二分枚举差,再枚举下界,上界=下界+差,在上下界的限制之下仍可到达终点,说明存在这么一个差,但是差还可能更小,所以继续二分。
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn = 205;
const int maxm = 1005;
const int inf = 1e6 + 5;
int n,m;
struct edge{
int t,speed;
};
vector<edge> G[maxn];
bool vis[maxn];
vector<int> speed;
void init(){
for(int i=1;i<=n;i++) G[i].clear();
speed.clear();
}
void add_edge(int u,int v,int cost){
G[u].push_back((edge){v,cost});
G[v].push_back((edge){u,cost});
}
void dfs(int v,int low,int up){
vis[v] = true;
for(int i=0;i<G[v].size();i++){
edge e = G[v][i];
if(e.speed >= low && e.speed <= up && !vis[e.t]){
dfs(e.t,low,up);
}
}
}
void solve(int s,int t){
double lb = 0,rb = inf;
while(rb - lb > 0.2){
double mid = (lb + rb) / 2;
bool flag = false;
for(int i=0;i<speed.size();i++){
CLR(vis,0);
dfs(s,speed[i],speed[i]+mid);
if(vis[t]){
flag = true;break;
}
}
if(flag) rb = mid;
else lb = mid;
}
if(rb == inf) printf("-1\n");
else printf("%d\n",(int)floor(rb));
}
int main(){
while(~scanf("%d%d",&n,&m)){
init();
int a,b,c;
while(m--){
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c);
speed.push_back(c);
}
sort(speed.begin(),speed.end());
speed.erase(unique(speed.begin(),speed.end()),speed.end());
int q;
scanf("%d",&q);
while(q--){
int s,t;
scanf("%d%d",&s,&t);
solve(s,t);
}
}
return 0;
}