标签:并查集 read geo getch lse back struct str gcd
题意:给出n个点,m条边,找出从s到t中某条路径上的最大值/最小值的比值最小,如果木有则输出不可能(英文),如果有,则输出最简分数形式
solve:
直接暴力枚举,给边进行权值排序。以某条边为最小值然后去更新能使s到达t的最大值,用并查集来判断两点是否连通
所以总的来说就是暴力+并查集(一开始头铁敲了个dfs直接T了emmm)
#include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <iostream> using namespace std; #define ll long long #define re register #define pb push_back const int N=1e6+10; void read(int &a) { a=0;int d=1;char ch; while(ch=getchar(),ch>‘9‘||ch<‘0‘) if(ch==‘-‘) d=-1; a=ch^48; while(ch=getchar(),ch>=‘0‘&&ch<=‘9‘) a=(a<<3)+(a<<1)+(ch^48); a*=d; } int f[N]; struct note{int u,v,w;}edge[N]; int getv(int v){return f[v]=v==f[v]?v:getv(f[v]);} bool cmp(note x,note y) {return x.w<y.w;} int gcd(int a,int b) {return !b?a:gcd(b,a%b);} int main() { int n,m; read(n),read(m); for(re int i=1;i<=n;i++) f[i]=i; for(re int i=1;i<=m;i++) { int x,y,w; read(x),read(y),read(w); int t1=getv(x),t2=getv(y); if(t1!=t2) f[t2]=t1; edge[i].u=x,edge[i].v=y,edge[i].w=w; } int s,t;read(s),read(t); if(getv(s)!=getv(t)) return puts("IMPOSSIBLE"),0; sort(edge+1,edge+1+m,cmp); int ans1=-1,ans2=-1; for(re int l=1;l<=m;l++) { bool flag=0; int r; for(re int i=1;i<=n;i++) f[i]=i; for(re int i=l;i<=m;i++) { int u=edge[i].u,v=edge[i].v; int t1=getv(u),t2=getv(v); if(t1!=t2) f[t2]=t1; if(getv(s)==getv(t)) { r=i; flag=1; break; } } if(flag) { if(ans1==-1&&ans2==-1) ans1=edge[r].w,ans2=edge[l].w; else if(ans1*edge[l].w>edge[r].w*ans2) ans1=edge[r].w,ans2=edge[l].w; } } int p=gcd(ans1,ans2); ans1/=p,ans2/=p; if(ans2==1) printf("%d\n",ans1); else printf("%d/%d\n",ans1,ans2); return 0; }
标签:并查集 read geo getch lse back struct str gcd
原文地址:https://www.cnblogs.com/acm1ruoji/p/12008764.html