洛谷P2502[HAOI2006]旅行

题目:##

Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光。Z小镇附近共有N个景点(编号为1,2,3,…,N),这些景点被M条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路。也许是为了保护该地的旅游资源,Z小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi。速度变化太快使得游客们很不舒服,因此从一个景点前往另一个景点的时候,大家都希望选择行使过程中最大速度和最小速度的比尽可能小的路线,也就是所谓最舒适的路线。

题目链接:旅行

输入:###

第一行包含两个正整数,N和M。

接下来的M行每行包含三个正整数:x,y和v。表示景点x到景点y之间有一条双向公路,车辆必须以速度v在该公路上行驶。

最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速度比最小的路径。s和t不可能相同。

输出:###

如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一个最简分数。

分析:###

并查集维护最小生成树,用kruskal跑,也算是并查集运用了吧(……)

对于这种求比值的题,我们可以枚举一个定值(最大值或者最小值),另外一个值跑最小生成树,根据最小生成树的性质可以得到当s和t连通的第一时刻加进去的那条边和前面定下来的值的比值就是这个定值的情况下的最优解
然后打个擂台找最小就可以了,用double存一下ans,然后最后输出的时候分子分母都要除以gcd
注意特判是整数的情况
没了


代码:

#include<bits/stdc++.h>
#define N 500+5
#define M 5000+5 
#define INF 1<<21
using namespace std;
int fa[N];
int n,m,s,t,l,r;
double ans=INF;
inline int read(){
	int cnt=0,f=1;char c;
	c=getchar();
	while(!isdigit(c)){
		if(c=='-')f=-f;
		c=getchar();
	}
	while(isdigit(c)){
		cnt=cnt*10+c-'0';
		c=getchar();
	}
	return cnt*f;
}
int find_father(int x){
	if(fa[x]==x)return x;
	return fa[x]=find_father(fa[x]);
}

int gcd(int a,int b){
	if(!b)return a;
	else return gcd(b,a%b);
}
struct node{
	int x;
	int y;
	int v;
}edge[M];
bool cmp(node a,node b){
	return a.v<b.v;
}
int main(){
	n=read();m=read();
	for(register int i=1;i<=n;i++)fa[i]=i;
	for(register int i=1;i<=m;i++){
		edge[i].x=read();
		edge[i].y=read();
		edge[i].v=read();
		int x=find_father(edge[i].x);
		int y=find_father(edge[i].y);
		if(x==y)continue;
		fa[x]=y;
	}
	s=read();t=read();
	if(find_father(s)!=find_father(t)){
		printf("IMPOSSIBLE");
		return 0;
	}
	sort(edge+1,edge+m+1,cmp);
	for(register int i=1;i<=m;i++){    //定下一条最小边,枚举比它大的边并不断往并查集里面加,当s和t连通时找到的是这条小边的最优解 
		for(register int j=1;j<=n;j++)fa[j]=j; 
		for(register int j=i;j<=m;j++){     //跑最小生成树(反正数据小怎么乱搞都行) 
			int x=find_father(edge[j].x);
			int y=find_father(edge[j].y);
			if(x!=y)fa[x]=y; 
//			cout<<s<<t;
			if(find_father(s)==find_father(t)){
//				cout<<l<<" "<<r<<endl;
				double sum=(double)edge[j].v/(double)edge[i].v;
//				cout<<sum<<endl;
				if(sum<ans){
					ans=sum;
					l=edge[j].v;
					r=edge[i].v;
				}
			}
		}
	}
	if(l%r==0)printf("%d",l/r);
	else{
		int t=gcd(l,r);
		printf("%d/%d",l/t,r/t);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/kma093/p/9932926.html