【穷举+并查集】BZOJ1050(HAOI2006)[旅行comf]题解

39 篇文章 2 订阅
15 篇文章 0 订阅

题目概述

给出n个点,m条双向边,每条边有边权,求一条s->t的路径,使得最大边权与最小边权的比值最小。

解题报告

我们有一个简单的初始想法,就是枚举MIN,然后二分枚举MAX,再用BFS判断s->t是否存在边权均在MIN~MAX内的路径。但是由于题目中的边权范围比较大,而每次BFS的效率是O(m),所以效率不是很高。其实有了这个想法,我们可以想到另外一种类似的想法:将边按照边权排序,然后枚举i和j,表示选择i~j的边,再检查s->t是否连通(其实就是变相枚举了MIN和MAX)。由于m不是特别大,所以这种想法是完全可行的!至于检查连通,用并查集即可。

示例程序

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=500,maxm=5000;

int n,m,st,gl,MIN,MAX,father[maxn+5];
double ans=1e100;
struct Edge
{
    int x,y,z;
    bool operator < (const Edge &c) const {return z<c.z;}
};
Edge e[maxm+5];

int getfa(int x)
{
    if (father[x]==x) return x;
    return father[x]=getfa(father[x]);
}
int gcd(int a,int b) {if (!b) return a; else return gcd(b,a%b);}
int main()
{
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
    scanf("%d%d",&st,&gl);
    sort(e+1,e+1+m);
    for (int i=1,j;i<=m;i++)
    {
        for (j=1;j<=n;j++) father[j]=j;
        for (j=i;j<=m;j++)
        {
            int fx=getfa(e[j].x),fy=getfa(e[j].y);
            if (fx!=fy) father[fx]=fy; else continue;
            if (getfa(st)==getfa(gl)) break;
        }
        if (getfa(st)!=getfa(gl)) break;
        //这里是个优化,getfa(st)!=getfa(gl)说明选i~m不满足,所以i+1~m肯定也不满足,不需要处理了
        if ((double)e[j].z/e[i].z<ans) MIN=e[i].z,MAX=e[j].z,ans=(double)MAX/MIN;
    }
    if (ans==1e100) {printf("IMPOSSIBLE\n");return 0;}
    int t=gcd(MIN,MAX);MAX/=t;MIN/=t;
    if (MIN==1) printf("%d\n",MAX); else printf("%d/%d\n",MAX,MIN);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值