hdu2363 Cycling(枚举或二分+最短路)

题目

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;
} 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值