题目
t(t<=100)组样例,每次给出n(1<=n<=100)个点,第i个点有海拔hi(0<=hi<=1e9),
m(0<=m<=5e3)条双向边,第j条边cj(1<=cj<=1e6)
求从点1到点n的路径中最高点高度与最低点高度之差最小的最短路
即第一关键字极差,第二关键字路径长
思路来源
https://blog.csdn.net/hexianhao/article/details/51437251
题解
①枚举:C(n,2)枚举最高点和最低点点对,按极差增序排列,
代表上下界,只对高度在此范围内的点跑最短路
考虑到n=1只有自己,所以也枚举i到i的n种情况
②二分:枚举下界,二分能连通的最小上界,更新最短路
实际写的时候,第一种略快
开始写了个枚举下界优先维护高度最小其次维护路径长度的最短路,WA到自闭
用图生成器Cyaron才看出点端倪,dijkstra有边的更新顺序,不能因为高度点改变顺序
代码
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=110,M=1e4+1e3;
using namespace std;
struct node
{
int d,v;
node(){}
node(int b,int c):d(b),v(c){}
};
bool operator<(node a,node b)
{
return a.d>b.d;
}
struct H
{
int mx,mn,dif;
}f[N*N];
bool operator<(H a,H b)
{
return a.dif<b.dif;
}
int t,n,m,u,v,w,tot,h[N],ans;
int head[N],cnt;
int dis[N],res;
bool vis[N];
struct edge{int to,nex;int w;}e[M];
priority_queue<node>q;
void init(int n)
{
cnt=tot=0;
for(int i=1;i<=n;++i)
head[i]=-1;
}
void add(int u,int v,int w)
{
e[cnt].to=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt++;
}
bool dijkstra(int u,int mn,int mx)
{
for(int i=1;i<=n;++i)
dis[i]=inf;
while(!q.empty())q.pop();
memset(vis,0,sizeof vis);
dis[u]=0;
if(!(mn<=h[u]&&h[u]<=mx))return 0;
q.push(node(dis[u],u));
while(!q.empty())
{
node tmp=q.top();
q.pop();
int pos=tmp.v;
if(vis[pos])continue;
vis[pos]=1;
for(int i=head[pos];~i;i=e[i].nex)
{
int v=e[i].to;
int w=e[i].w;
if(!(mn<=h[v]&&h[v]<=mx))continue;
if(dis[v]>dis[pos]+w)
{
dis[v]=dis[pos]+w;
q.push(node(dis[v],v));
}
}
}
return dis[n]!=inf;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init(n);
ans=res=inf;
for(int i=1;i<=n;++i)
scanf("%d",&h[i]);
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
for(int i=1;i<=n;++i)
{
for(int j=i;j<=n;++j)//n=1的情形 故考虑自身
{
f[++tot].mx=max(h[i],h[j]);
f[tot].mn=min(h[i],h[j]);
f[tot].dif=f[tot].mx-f[tot].mn;
}
}
sort(f+1,f+tot+1);
for(int i=1;i<=tot;++i)//最多5k次dijkstra
{
int dif=f[i].dif,mn=f[i].mn,mx=f[i].mx;
if(dif>ans)break;
if(dijkstra(1,mn,mx))
{
if(dif<ans||(dif==ans&&dis[n]<res))
{
ans=dif;
res=dis[n];
}
}
}
printf("%d %d\n",ans,res);
}
return 0;
}