题意:n个城市m条路,每条路上开车有个速度,要你求从start到end最高速度与最低速度的最小之差;
给出两种求得方法第二种有问题
代码1:用并查集枚举高度差,其实这里是去掉一部分边,然后跑克鲁斯卡尔。思路写在代码注释上
/*
题意:输入n和m 然后m条边,u v a 表示u到v这条路上的速度是a。要你求 输入从start到end
最快速度与最慢速度相差最小的差。
思路:先将边排序,然后去掉一些边,再跑克鲁斯卡尔,边跑的时候变判断start点和end点在不在同一个连通模块,
如果在的话,就不用继续克鲁斯卡尔了,因为在往后面最大的边一直增大,所以差值也变大。然后从小到大去掉边,
最后找一个最小的差值。
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
using namespace std;
struct edge{
int from,to,w;
};
int n,m;
vector<edge>edges;
int pre[210];
bool cmp(edge a,edge b)
{
return a.w<b.w;
}
void addedge(int x,int y,int w)
{
edge v={x,y,w};
edges.push_back(v);
}
int find(int x)
{
if(pre[x]==x)
{
return x;
}
else
{
pre[x]=find(pre[x]);
return pre[x];
}
}
int kluska(int start,int end1)
{
int ans=999999999;
for(int i=0;i<edges.size();i++)
{ for(int i=1;i<=n;i++)
{
pre[i]=i;
}
for(int j=i;j<edges.size();j++)
{ edge v=edges[j];
int f1=find(v.from);
int f2=find(v.to);
if(f1!=f2)
{
pre[f2]=f1;
}
if(find(start)==find(end1))
{
if(ans>v.w-edges[i].w)
{
ans=v.w-edges[i].w;
}
break;
}
}
}
if(ans==999999999)
{
printf("-1\n");
}
else printf("%d\n",ans);
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{ edges.clear();
for(int i=1;i<=m;i++)
{
int x,y,w;
scanf("%d %d %d",&x,&y,&w);
addedge(x,y,w);
}
int q;
scanf("%d",&q);
int start,end1;
sort(edges.begin(),edges.end(),cmp);
for(int i=1;i<=q;i++)
{
scanf("%d %d",&start,&end1);
kluska(start,end1);
}
}
}
代码二:二分高度差加最短路
/*
这种思路是,二分枚举高度差,然后跑最短路,但是这种方法是有问题的,hud没有测出来。
mid 就是高度差,然后枚举边求得最小高度,和最大高度,然后跑最短路的时候假如这两个条件的限制即可。
这组数据用着种方法做就有问题
3 2
1 2 3
2 3 10
1
1 3
这里的答案为-1
但是正确的答案为7
但杭电测不出
*/
#include <iostream>
#include <algorithm>
#include <queue>
#include<stdio.h>
using namespace std;
#define inf 0x3fffffff
#define M 205 //最大点数
struct son{
int v, w;
};
vector<son> g[M];
bool inq[M]; //入队列标记
int dist[M], tp[1005], n; //n:实际点数
void init ()
{
for (int i = 1; i <= n; i++)
g[i].clear();
}
bool spfa (int u, int low, int high, int t)
{
int i, v, w;
for (i = 1; i <= n; i++)
{
dist[i] = inf;
inq[i] = false;
}
queue<int> q;
q.push (u);
inq[u] = true;
dist[u] = 0;
while (!q.empty())
{
u = q.front();
q.pop();
inq[u] = false;
for (i = 0; i < g[u].size(); i++)
{
v = g[u][i].v;
w = g[u][i].w;
if (w < low || w > high) //限制条件
continue;
if (dist[u] + w < dist[v])
{
if (v == t) //可以到达终点返回true
return true;
dist[v] = dist[u] + w;
if (!inq[v])
{
q.push (v);
inq[v] = true;
}
}
}
}
return false;
}
int main()
{
bool flag;
int m, u, v, i, l, r, mid, maxs;
son x;
while (~scanf ("%d%d", &n, &m))
{
init();
maxs = 0;
for (i = 0; i < m; i++)
{
scanf ("%d%d%d", &u, &v, tp+i);
if (maxs < tp[i])
maxs = tp[i];
x.v = v, x.w = tp[i];
g[u].push_back (x);
x.v = u;
g[v].push_back (x);
}
sort (tp, tp+m); //边的权值从小到大排序
int q;
scanf ("%d", &q);
while (q--)
{
scanf ("%d%d", &u, &v);
l = 0, r = maxs;
int ans = -1;
while (l <= r) //二分枚举舒适度差
{
flag = false;
mid = (l+r) >> 1; //mid就是差
for (i = 0; tp[i] + mid <= maxs; i++)
{
if (spfa (u, tp[i], tp[i]+mid, v))
{
flag = true;
break;
}
}
if (flag)
ans = mid, r = mid - 1;
else l = mid + 1;
}
printf ("%d\n", ans);
}
}
return 0;
}