hdu 1598 find the most comfortable road 并查集+贪心

本文介绍了一种通过枚举最小权重边来求解有向图中从起点到终点路径的最小权重差的方法,利用并查集判断图是否连通。适用于图中点数不超过200的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://acm.hdu.edu.cn/showproblem.php?pid=1598

题意:给定有向图和起点和终点,求从起点到终点的路径中,权重最大和最小的边的最小差。

思路:很好的一道题目。一开始看到图的点数最多为200个的时候想到可以用floyd做,但是后来就发现其实最小差并没有最优子问题的性质,也就是说用dis[i][j]表示i和j之间的最小差,在dis[i][j]取到最优的时候,并不一定是dis[i][k] 和 dis[k][j] 取到最优的时候,因此这里我们并不能用floyd。这里我们可以这样考虑,在每次给定一对起点和终点的时候,因为只有1000条边, 我们可以考虑依次枚举最小的权重, 然后每次添加一条边, 直到起点和终点连通为止,此时由最大边就可以得出一个差值,这样一次枚举所有的可能就可以得出最终的最优解。这里判断图是否连通可以用并查集的方法。

代码: 

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int INF = 0x3f3f3f3f ;
int N , M ,Q;
struct Node{
	int s,e,d ;
}edge[1010] ;
bool comp(Node n1, Node n2){
	return n1.d < n2.d;
}
int f[210] ;
void Init(){
	for(int i=1;i<=N;i++)
		f[i] = i ;
}
int find(int a){
	if(a != f[a]){
		f[a] = find( f[a] ) ;
	}
	return f[a] ;
}
void Union(int a, int b){
	int fa = find(a) ;
	int fb = find(b) ;
	if(fa == fb)	return ;
	if(fa < fb){
		f[fb] = fa ;
	}
	else
		f[fa] = fb;
}
int main(){
	int a, b,c ;
	while(scanf("%d %d",&N,&M) == 2){
		for(int i=0;i<M;i++){
			scanf("%d %d %d",&a,&b,&c);
			edge[i].s = a  ;
			edge[i].e = b ;
			edge[i].d = c ;
		}
		sort(edge,edge+M,comp);
		scanf("%d",&Q);
		for(int i=1;i<=Q;i++){
			int u ,v ;
			int ans = INF ;
			scanf("%d %d",&u,&v);
			for(int j=0;j<M;j++){
				Init() ;
				int minlen = edge[j].d ,maxlen;
				for(int k=j;k<M;k++){
					a = edge[k].s ;
					b = edge[k].e ;
					c = edge[k].d ;
					Union(a,b) ;	
					if(find(u) == find(v)){
						maxlen = edge[k].d ;
						if(ans > maxlen - minlen){
							ans = maxlen - minlen;
						}
						break ;	
					}
				}
			}
			if(ans == INF)
				ans = -1 ;
			printf("%d\n",ans);
		}
	}		
	return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值