导航

题解 洛谷 P2502 【[HAOI2006]旅行】

给出一张无向图,给出一个s,t使得这条路上最大值和最小值的比值最最小,并且输出既约分数(即最简分数)


并查集做法:

枚举最小值,找最大值。每次加入直到可以联通,这时比较ans大小,能更新则更新。

ans更新时是分数比大小,直接两个分子乘上互相的分母即可。


Code:

#include <bits/stdc++.h>
using namespace std;
int f[1000005],n,m,x,y,z,s,t,ans1=30001,ans2=1;bool flag=false;
struct edge{
	int u,v,w;
} e[100005];
// 结构体存图,u,v:两条边,w:权值 
inline void init(int n){for(int i=1;i<=n;++i)f[i]=i;}//并查集初始化 
inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}//查询操作 
inline bool cmp(edge x,edge y){return x.w<y.w;}//cmp比较函数,按照权值大小进行升序排序 
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		scanf("%d%d%d",&x,&y,&z);
		e[i].u=x,e[i].v=y,e[i].w=z;
		//输入图 
	}
	scanf("%d%d",&s,&t);
	sort(e+1,e+1+m,cmp);
	//排序 
	for(int min_index=1;min_index<=m;++min_index){
		//枚举最小值下标 
		init(n);flag=false;//flag代表每次是否更新ans 
		int max_index=min_index;
		for(max_index=min_index;max_index<=m;++max_index){
			//最大值下标 
			int p=find(e[max_index].u),q=find(e[max_index].v);
			if(p!=q)f[p]=q;
			// 将两个元素合并,效果等于奆佬们常写的merge 
			if(find(s)==find(t))
			{flag=true;break;}
			//假如两个点联通,又因为升序排了权值,所以此时的解必然是当前min_index和max_index里的最小值 
		}
		if(flag)if(ans1*e[min_index].w>ans2*e[max_index].w)ans1=e[max_index].w,ans2=e[min_index].w;
		// 分数比大小 
	}
	if(ans1==30001)puts("IMPOSSIBLE");
	// 假如ans没有被更新,则没有联通,输出"IMPOSSIBLE" 
	else{
		int com=__gcd(ans1,ans2);
		ans1/=com,ans2/=com;
		// 即约分数,化简分数 
		if(ans2==1)printf("%d\n",ans1);
		// 若分母为1,直接输出分子 
		else printf("%d/%d\n",ans1,ans2);
	}
	return 0;
}




posted on 2021-01-04 22:14  ExcaliburGod  阅读(66)  评论(0)    收藏  举报