P2502 [HAOI2006]旅行
Sol:
- 暴力
枚举所有从S到T的路径,然后用maxw/minw更新答案。
时间复杂度:\(O(玄学)\)
- 正解
观察到边数\(m\leq5000\)
考虑由直接求maxw和minw -> 枚举minw求maxw
由于从S到T的路径上的最大值最小的边一定在最小生成树上(最小生成树的瓶颈路性质),所以我们可以将边从小到大排序,每次枚举边\(e_i\),并将剩下的\(e_i,e_{i+1}\dots e_m\)建最小生成树,当边\(e_k\)使S和T第一次连通时,用\(e_k/e_i\)更新答案。
AC Code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int read(){
int x=0,f=1;char ch=‘ ‘;
while(ch>‘9‘||ch<‘0‘) {if(ch==‘-‘) f=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘) {x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();}
return x*f;
}
const int N = 500 + 100,M = 5000 + 100;
int n,m,s,t;
struct node{
int u,v,w;
bool operator < (const node& a)const{
return w<a.w;
}
}e[M];
int gcd(int a,int b){
return !b?a:gcd(b,a%b);
}
int fa[N];
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
double tmpmax;
int ansmax,ansmin;
bool ok;
void kruskal(int l){
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=l;i<=m;i++){
int u=e[i].u,v=e[i].v,w=e[i].w;
int p=find(u),q=find(v);
if(p!=q){
fa[p]=q;
}
if(find(s)==find(t)){
tmpmax=w;
ok=0;
break;
}
}
return ;
}
int main(){
// freopen("data.in","r",stdin);
// freopen("sol.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;i++) fa[i]=i;
int tot=0;
for(int i=1;i<=m;i++){
int u,v,w;u=read();v=read();w=read();
e[i]=(node){u,v,w};
fa[find(u)]=find(v);
}
sort(e+1,e+m+1);
s=read();t=read();
if(find(s)!=find(t)){
printf("IMPOSSIBLE");return 0;
}
double ans=10000000.0;
for(int i=1;i<=m;i++){
ok=1;
kruskal(i);
if(ok) continue;//S与T不连通
double res=tmpmax/e[i].w;
if(res<ans){
ansmin=e[i].w;
ansmax=floor(tmpmax);
ans=min(ans,res);
}
}
if(ansmax%ansmin==0){
printf("%d",ansmax/ansmin);
}
else{
int GCD=gcd(ansmin,ansmax);
ansmin/=GCD,ansmax/=GCD;
printf("%d/%d",ansmax,ansmin);
}
return 0;
}
原文地址:https://www.cnblogs.com/Loi-Brilliant/p/9757908.html
时间: 2024-09-29 21:51:27