BZOJ1050 [HAOI2006]旅行comf

题目描述:

给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000)。给你两个顶点S和T,求
一条路径,使得路径上最大边和最小边的比值最小。如果S和T之间没有路径,输出”IMPOSSIBLE”,否则输出这个
比值,如果需要,表示成一个既约分数。 备注: 两个顶点之间可能有多条路径。
 
题解:
我们想如何贪心。
既然要比值最小,那么我们找到尽量小的最大边和尽量大的最小边就行了。
那怎么找呢?
我们将每个边权排序,每次枚举最小边和最大边,并将其加入并查集,如果将起点和中点连在了同一个联通块中,就是符合答案的一组解了。
附上代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,s,t,f[5001],flag,idx,cnt1,cnt2;
double ans=999999999.0;
struct Edge
{
    int l,r,v;
}a[5001];
bool cmp(const Edge &x,const Edge &y)
{
    return x.v<y.v;
}
int find(int p)
{
    if(f[p]!=p)
        f[p]=find(f[p]);
    return f[p];
}
void merge(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
        f[fx]=fy;
}
int gcd(int x,int y)
{
    if(x%y==0)
        return y;
    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].l,&a[i].r,&a[i].v);
    scanf("%d%d",&s,&t);
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        flag=0;
        for(int j=1;j<=n;j++)
            f[j]=j;
        for(int j=i;j<=m;j++)
        {
            merge(a[j].l,a[j].r);
            if(find(s)==find(t))
            {
                idx=j;
                flag=1;
                break;
            }
        }
        if(flag==1)
        {
            if(ans>(a[idx].v*1.0)/a[i].v)
            {
                ans=(a[idx].v*1.0)/a[i].v;
                cnt1=a[idx].v;
                cnt2=a[i].v;
            }
        }
    }
    if(ans==999999999.0)
    {
        printf("IMPOSSIBLE");
        return 0;
    }
    int k=gcd(cnt1,cnt2);
    if(cnt2/k==1)
        printf("%d",cnt1/k);
    else
        printf("%d/%d",cnt1/k,cnt2/k);
}

 

posted @ 2018-10-24 14:17  jiangminghong  阅读(58)  评论(0编辑  收藏