hdu2363 枚举+最短路 好题

这道题目一开始我的思路就是错了,前前后后挣扎了n个小时。。。开始的想法是dijkstra,通过二分枚举高度差。但是发现一个问题,就是因为dijkstra里面优先选择的是短的路。我直接二分高度差,是有两个限制条件。然后就想到spfa,后来仔细想了想还是不行。。。最后用dfs了,才100个点嘛,感觉稳了,结果又tle。。。。。。。

开了别人的题解一眼,恍然大悟。有两个限制条件(用于选择)的最短路怎么能求呢?

所以本题的思路是,枚举任意的两个点,两个点的高度分别当作是low和up

另外注意判断1==N的情况。。。真是无力吐槽了。。。

 

AC的代码

//通过枚举最小边还是不行 
#include <bits/stdc++.h>
using namespace std;
#define res register int 
#define ll long long 
#define inf 0x3f3f3f3f
const int maxn=105;
int N,M,h[maxn];
int G[maxn][maxn];
int dis[maxn],vis[maxn]; 
int low,up;
int result;

struct Node{
	int low,up;
}node[maxn*maxn];
bool operator<(const Node a,const Node b){
	if(a.up-a.low!=b.up-b.low)
		return a.up-a.low<b.up-b.low;
	else	
		return a.up<b.up;
}	

bool spfa() 
{
	int flag=0;
	memset(dis,inf,sizeof(dis));
	memset(vis,0,sizeof(vis));
	queue<int> q;
	q.push(1);
	vis[1]=1;
	dis[1]=0;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		vis[x]=0;
		for(res i=1;i<=N;i++){
			int y=i;
			if(y!=x&&dis[y]>dis[x]+G[x][y]&&low<=h[y]&&h[y]<=up){
				dis[y]=dis[x]+G[x][y];
				if(N==y){
					result=min(result,dis[N]);
					flag=1;
				}
				if(!vis[y]){
					q.push(y);
					vis[y]=1;
				}
			}
		} 
	}
	if(0==flag) return false;
	else return true;
}


int main()
{
	int T;
	scanf("%d",&T);
	while(T--){
		//init
		memset(vis,0,sizeof(vis));
		scanf("%d%d",&N,&M);
		for(res i=1;i<=N;i++){
			scanf("%d",&h[i]);
			for(res j=1;j<=N;j++){
				if(i!=j) G[i][j]=G[j][i]=inf;
				else G[i][j]=0;
			}
		}
		int a,b,v;
		for(res i=1;i<=M;i++){
			scanf("%d%d%d",&a,&b,&v);
			if(v<G[a][b]) G[a][b]=G[b][a]=v;
		}
		//init
		int ans=1;
		for(res i=1;i<=N;i++){
			for(res j=1;j<=N;j++){
				if(i!=j){
					node[ans].up=max(h[i],h[j]);
					node[ans++].low=min(h[i],h[j]);
				}
			}
		}
		node[ans].low=h[1];
		node[ans++].up=h[1];
		sort(node+1,node+1+ans);
		int i,temp=-1;
		int flag=0,pre=inf;
		result=inf; 
		node[0].low=node[0].up=-1;
		for(i=1;i<ans;i++){
			if(node[i].up==node[i-1].up&&node[i].low==node[i-1].low) continue;
			if(flag&&node[i].up-node[i].low>pre) break;
			low=node[i].low,up=node[i].up;
			if(low>h[1]||low>h[N]||up<h[1]||up<h[N]) continue;
			if(spfa()){
				flag=1;
				pre=node[i].up-node[i].low;
			}
		}
		if(1==N) printf("%d %d\n",0,0);
		else  printf("%d %d\n",pre,result);
	}
	return 0;	
}
		

tle的dfs

#include <bits/stdc++.h>
using namespace std;
#define res register int 
#define ll long long 
#define inf 0x3f3f3f3f
const int maxn=105;
int N,M,h[maxn];
int G[maxn][maxn];
int dis[maxn],vis[maxn]; 
int Max[maxn],Min[maxn];
int result,flag=0;

void dfs(int n,int H,int Maxh,int Minh){
	if(n==N){
		result=min(dis[N],result);
		flag=1;
		return;
	}	
	for(res i=1;i<=N;i++){
		if(i!=n&&!vis[i]&&dis[i]>dis[n]+G[i][n]&&max(Maxh,h[i])-min(Minh,h[i])<=H){
			int temp=dis[i];
			dis[i]=dis[n]+G[i][n]; 
			vis[i]=1;
			dfs(i,H,max(Maxh,h[i]),min(Minh,h[i]));
			vis[i]=0;
			dis[i]=temp;
		}		
	}	
	return;
} 


int main()
{
	int T;
	scanf("%d",&T);
	while(T--){
		//init
		result=inf;
		scanf("%d%d",&N,&M);
		int Maxh=0,Minh=inf;
		for(res i=1;i<=N;i++){
			scanf("%d",&h[i]);
			Maxh=max(Maxh,h[i]);Minh=min(Minh,h[i]);
			for(res j=1;j<=N;j++){
				if(i!=j) G[i][j]=G[j][i]=inf;
				else G[i][j]=0;
			}
		}
		int a,b,c;
		for(res i=1;i<=M;i++){
			scanf("%d%d%d",&a,&b,&c);
			if(c<G[a][b]) G[a][b]=G[b][a]=c;
		}
		//init
		int l=abs(h[N]-h[1]),r=Maxh-Minh;
		while(l<=r){
			int mid=(l+r)>>1;
			result=inf;
			memset(vis,0,sizeof(vis));
			memset(dis,inf,sizeof(dis));
			dis[1]=0;
			vis[1]=1;
			flag=0;		
			dfs(1,mid,h[1],h[1]);	
			if(flag){
				r=mid-1;
			}else{
				l=mid+1;
			}
		}
		printf("%d %d\n",l,result);
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值