BZOJ1050 HAOI2006 旅行comf 生成树+枚举
题意:给订一张无向图,求一条S到T的路径,使得路径上的最大边权与最小边权的比值最小
题解:将边由小到大排序,暴力枚举最小边,然后借鉴Kruskal的思想,由小到大加入每一条大于初始边的边,检验S与T是否连通,若连通则更新答案,枚举下一条边。
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=500+2; const int MAXM=5000+2; struct EDGE{ int u,v,w; }e[MAXM]; int N,M,S,T,f[MAXN],ans_max,ans_min; bool flag; int gcd(int a,int b){ return !b?a:gcd(b,a%b);} bool cmp(EDGE a,EDGE b){ return a.w<b.w;} int Find(int x){ return x==f[x]?x:f[x]=Find(f[x]);} int main(){ cin >> N >> M; for(int i=1;i<=M;i++) cin >> e[i].u >> e[i].v >> e[i].w; sort(e+1,e+M+1,cmp); cin >> S >> T; for(int i=1,j;i<=M;i++,flag=0){ if(e[i].w==e[i-1].w) continue; for(j=1;j<=N;j++) f[j]=j; for(j=i;j<=M;j++){ if(Find(e[j].u)!=Find(e[j].v)) f[Find(e[j].u)]=f[Find(e[j].v)]; if(Find(S)==Find(T)){ flag=1; break; } } if(flag && (i==1 || ans_max*e[i].w>e[j].w*ans_min)) ans_min=e[i].w,ans_max=e[j].w; } if(!ans_min) cout << "IMPOSSIBLE" << endl; else{ int t=gcd(ans_max,ans_min); ans_max/=t,ans_min/=t; if(ans_min==1) cout << ans_max << endl; else cout << ans_max << "/" << ans_min << endl; } return 0; }