BZOJ 1050: [HAOI2006]旅行comf (并查集 或 单调队列)

这是建空间后做的第一道题啊= =好水

排序,枚举最小边,然后并查集求出联通时的最大边

或者排次序,从小到大插边,如果插边时最小的边拿掉不会使s与t不联通,就删去。

 

code:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node{
    int x,y,dist;
}a[5010];
int n,m,s,t,f[510],ansi,ansa;
bool cmp(node x,node y){return x.dist<y.dist;}
int find(int x){if (x!=f[x]) f[x]=find(f[x]);return (f[x]);}
int gcd(int x,int y){
    if (!y) return x;
    return gcd(y,x %y);
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].dist);
    sort(a+1,a+1+m,cmp);
    scanf("%d%d",&s,&t);
    ansi=a[1].dist;ansa=40000;
    for (int i=1;i<=n;i++) f[i]=i;
    for (int i=1;i<=m;i++) {
        int x=find(a[i].x),y=find(a[i].y);
        if (x!=y) f[x]=y;
        x=find(s);y=find(t);
        if (x==y) {
            ansa=a[i].dist;
            break;
        }
    }
    if (ansa==40000) {printf("IMPOSSIBLE\n");return 0;}
    for (int i=2;i<=m;i++) {
        for (int j=1;j<=n;j++) f[j]=j;
        for (int j=i;j<=m;j++) {
            int x=find(a[j].x),y=find(a[j].y);
            if (x!=y) f[x]=y;
            x=find(s);y=find(t);
            if (x==y) {
                if (ansa*1.0/ansi>a[j].dist*1.0/a[i].dist) {ansa=a[j].dist;ansi=a[i].dist;}
                break;
            }
        }
    }
    int t=gcd(ansa,ansi);
    if (ansa*1.0/ansi==ansa/ansi) printf("%d\n",ansa/ansi);
    else printf("%d/%d",ansa/t,ansi/t);
    return 0;
}

 

posted @ 2014-06-08 17:24  New_Godess  阅读(111)  评论(0编辑  收藏  举报