洛谷 P2502 旅行 SSL 1312 (并查集暴力)
题目描述:
解题思路:
遇到这种,在满足某种条件下找最值的问题:如这题,在一条能够从起始点到达目标点的路径中找到比值最小的最大值和最小值。我们往往会先枚举这些可行的路径,然后在路径里面找到最大值和最小值,这样子的话很难找到头绪。
我们可一个换个思路,枚举路径的权值的最小值的下限
i
i
i 和最大值的上限
j
j
j
然后把符合这个上下限权值条件的边上的点所在的集合都按边的关系合并,也就是说若
a
a
a 和
b
b
b 之间有一条满足条件的边,则将
a
a
a 和
b
b
b 所在的集合合并。
如图:
我们可以在最小边权
i
i
i 到最大边权
j
j
j 的区间内选边进行构造路径。
最后判断选用的这些边构成的路径是否能从起始点道目标点,也就是说判断合并后起始点是否和目标点在一个集合。
若能,则尝试用
i
i
i 和
j
j
j 更新最小值和最大值;若不能,则枚举下一个最小值最大值区间。
因此我们不断枚举并改变边权的上下限,在满足从起始点到目标点能构成路径的那些上下限内进行最优选择,找到比值最小的一组上下限即为答案。
由于要枚举上下限区间,因此很显然我们要将边按照边权排序,然后枚举边权的下限以及上限,一次来推出我们的边权区间范围,最后通过合并集合来判断是否构成路径。
CODE:
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
int n,m,s,f,x,y;
double minn=0.0;
int fa[1010];
struct Gar
{
int x,y,v;
} e[5010];
bool cmp(Gar a,Gar b) //按边权从小到大排序
{
return a.v<b.v;
}
int find(int x) //查找集合代表元素
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
void join(int x,int y) //合并集合
{
fa[find(x)]=fa[find(y)];
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>e[i].x>>e[i].y>>e[i].v;
cin>>s>>f;
sort(e+1,e+m+1,cmp);
minn=1e9*1.0;
for(int i=1;i<=m;i++) //枚举最小边权的边
{
for(int j=1;j<=n;j++) fa[j]=j;
int j=i;
bool flag=false;
while(true) //枚举最大的边
{
if(j>m) break;
join(e[j].x,e[j].y); //将选用的边的两个点的集合合并
if(find(s)==find(f)) //表示找到一条路径从起始点到达目标点
{
flag=true;
break;
}
j++; //由于边权排序,因此越往后越大,直接枚举下一个最大边即可
}
if(flag)
{
if(double(e[j].v)/double(e[i].v)<minn) //存下最小的比值
{
minn=double(e[j].v)/double(e[i].v)*1.0;
x=e[i].v;
y=e[j].v;
}
}
}
if(minn!=1e9)
{
if(y%x==0) cout<<y/x;
else
cout<<y/__gcd(x,y)<<"/"<<x/__gcd(x,y); //输出最简分数形式
return 0;
}
cout<<"IMPOSSIBLE";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!