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;
}
View Code

 

posted @ 2017-02-27 23:02  WDZRMPCBIT  阅读(38)  评论(0编辑  收藏