首页 > 代码库 > BZOJ 1050 旅行(并查集)

BZOJ 1050 旅行(并查集)

很好的一道题。

首先注意,要使的s到t的路径上最大边/最小边的值最小。我们可以尝试一下二分并验证答案。

但是不能二分最大边/最小边。 我们可以二分 最小边的权值。于是算法就出来了。

首先把边权排序。然后枚举最小的边,再依次添加不小于该边的边,直到s和t联通。用并查集维护即可。

 

技术分享
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 998244353
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
# define set pabs
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())==-) flag=1;
    else if(ch>=0&&ch<=9) res=ch-0;
    while((ch=getchar())>=0&&ch<=9)  res=res*10+(ch-0);
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar(-); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+0);
}
const int N=505;
//Code begin...
typedef struct{int u, v, w;}Node;
Node edge[5005];
int fa[N];

bool comp(Node a, Node b){return a.w<b.w;}
int find(int x)
{
    int s, temp;
    for (s=x; fa[s]>=0; s=fa[s]) ;
    while (s!=x) temp=fa[x], fa[x]=s, x=temp;
    return s;
}
void union_set(int x, int y)
{
    int temp=fa[x]+fa[y];
    if (fa[x]>fa[y]) fa[x]=y, fa[y]=temp;
    else fa[y]=x, fa[x]=temp;
}
int gcd(int x, int y){return y?gcd(y,x%y):x;}
int main ()
{
    int n, m, u, v, mi, ma, s, t, ans[2];
    double answer=INF;
    scanf("%d%d",&n,&m);
    FOR(i,1,m) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
    scanf("%d%d",&s,&t);
    sort(edge+1,edge+m+1,comp);
    FOR(i,1,m) {
        mem(fa,-1);
        mi=edge[i].w; ma=0;
        FOR(j,i,m) {
            u=edge[j].u, v=edge[j].v;
            if (find(u)!=find(v)) union_set(find(u),find(v));
            if (find(s)==find(t)) {ma=edge[j].w; break;}
        }
        if (ma) if (answer>(double)ma/mi) answer=(double)ma/mi, ans[0]=ma/gcd(ma,mi), ans[1]=mi/gcd(ma,mi);
    }
    if (fabs(answer-INF)<eps) puts("IMPOSSIBLE");
    else {
        if (ans[1]==1) printf("%d\n",ans[0]);
        else printf("%d/%d\n",ans[0],ans[1]);
    }
    return 0;
}
View Code

 

BZOJ 1050 旅行(并查集)