BZOJ1050 [HAOI2006]旅行comf[并查集判图连通性]

Description

给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000)。给你两个顶点S和T,求
一条路径,使得路径上最大边和最小边的比值最小。如果S和T之间没有路径,输出”IMPOSSIBLE”,否则输出这个
比值,如果需要,表示成一个既约分数。 备注: 两个顶点之间可能有多条路径。

体现了并查集实际作用的一道题,也就是判图连通性。几句总结:

最小化或最大化一个分数时通常可以二分,但是也可以去设法最大or最小化分子分母。二分不好check的话就可以尝试后者。


据说二分带点优化其实是可以的,然而我不会。根据上面那则提示,因为最大边和最小边无法同时分别最小和最大化,所以可以先固定分母(最小边)。然后要求分子尽可能小。就是说找大于最小边的一些边让s到t连通,最小化那个最大边。那么对于最小的最大边,只要从最小边开始从小到大不停加边,直到s与t连通时立即停止即可,找到的一定是最小的最大边,正确性很容易证(最小的可行解之前的所有边都无法使其连通,而当前为第一个可行解,即最小)。于是枚举最小边并查集维护连通性就行,$O(N^{2}α(N))$稍有点卡,但是能过。可以把除法比较转换成乘法比较加一点速。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 #define dbg(x) cerr<<#x<<" = "<<x<<endl
 8 #define ddbg(x,y) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<endl
 9 using namespace std;
10 typedef long long ll;
11 typedef double db;
12 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
13 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
16 template<typename T>inline T read(T&x){
17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
19 }
20 const int N=5000+7;
21 struct thx{
22     int u,v,w;
23     inline bool operator <(const thx&orz)const{
24         return w<orz.w;
25     }
26 }e[N];
27 int fa[N],n,m,s,t,p=300000,q=1;
28 inline int Get(int x){return fa[x]^x?fa[x]=Get(fa[x]):x;}
29 inline int gcd(int a,int b){return b?gcd(b,a%b):a;}
30 
31 int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
32     read(n),read(m);
33     for(register int i=1;i<=m;++i)read(e[i].u),read(e[i].v),read(e[i].w);
34     sort(e+1,e+m+1);read(s),read(t);
35     for(register int i=1;i<=m;++i){
36         int j;for(j=1;j<=n;++j)fa[j]=j;
37         for(j=i;j<=m;++j){
38             fa[Get(e[j].u)]=Get(e[j].v);
39             if(Get(s)==Get(t))break;
40         }
41         if(Get(s)==Get(t))if(p*e[i].w>q*e[j].w)p=e[j].w,q=e[i].w;
42     }
43     if(p>30000)printf("IMPOSSIBLE\n");
44     else p%q==0?printf("%d",p/q):printf("%d/%d\n",p/gcd(p,q),q/gcd(p,q));
45     return 0;
46 }

 

posted @ 2019-04-02 17:52  Ametsuji_akiya  阅读(158)  评论(0编辑  收藏  举报