CODEVS 1001 舒适的路线 题解


#include<bits/stdc++.h>
using namespace std;
struct edge
{
    int w,u,v;
    edge(int weight,int from,int to):w(weight),u(from),v(to){}
};

struct ans
{
    int w1,w2;
    ans(int ws,int wb):w1(ws),w2(wb){}
};

bool mycmp(edge a,edge b)
{
    return(a.w<b.w);
}

vector<edge> e;
int p[550];

void init(int setsize)
{
    for(int i=1;i<=setsize;i++){
        p[i]=i;
    }
}

int get(int x)
{
    return(x==p[x]?x:p[x]=get(p[x]));
}

int unite(int x,int y)
{
    int a=get(x); int b=get(y);
    p[a]=b;
}

int gcd(int m,int n)
{
    int r;
    do{
    r=m%n;
    m=n;
    n=r;
    }while(r!=0);
    return m;
}

int main()
{
    int n,m,s,t;
    ans a=ans(1,INT_MAX-1);
    cin>>n>>m;
    e.clear();
    init(n);
    for(int i=0;i<m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        e.push_back(edge(w,u,v));
    }
    cin>>s>>t;
    /*判断是否存在路径*/
    bool ok=false;
    for(int i=0;i<m;i++){
        const edge& st=e[i];
        unite(st.u,st.v);
        if(get(s)==get(t)){ok=true;init(n);break;}
    }
    if(not ok){cout<<"IMPOSSIBLE"<<endl; return 0;}
    sort(e.begin(),e.end(),mycmp);
    //cout<<e[2].w<<endl;
    /*开始枚举*/
    for(int i=0;i<m;i++){
        init(n);
        const int& w1=e[i].w;
        for(int j=i;j<m;j++){
            unite(e[j].u,e[j].v);
            if(get(s)==get(t)){
                const int& w2=e[j].w;
                if((double)w2/w1<(double)a.w2/a.w1){a=ans(w1,w2);break;}
            }
        }
    }
    /*约分后输出即可*/
    int gcdnum=gcd(a.w2,a.w1);
    if(a.w1==gcdnum)cout<<a.w2/gcdnum<<endl;
    else cout<<a.w2/gcdnum<<"/"<<a.w1/gcdnum<<endl;
    return 0;
}

题意:给定n个点、m条边的带权无向图,求从点s到点t的一条路径,使得路径上所有边权的最大值与最小值之比最小,输出该比值即可(若不存在,输出”IMPOSSIBLE”)。n<=500,m<=5000,s<>t。

我考虑过用DP、Bellman-ford之类的方法同时维护路径的最大值与最小值,但感觉做不下去。于是想到类似Kruskal算法的解法:按权值从小到大对边进行排序。从小到大枚举所有边:设当前选择的边权值为w1,从该边开始,从小到大将边的左右端点合并到一个联通分量中,直到点s、t连通为止。记下最后选择的边的权值w2。比较w2/w1与当前的最小比值,若更优,则将最小比值更新为w2/w1。枚举完成后即可获得答案。

这里存在一个问题:假设我们当前选择了边i,合并到边j时s、t连通,边i有可能并不存在于s到t的路径上!这意味着我们计算的wj/wi也许根本就无意义。但,这并不会影响算法的正确性。我们分两种情况证明该算法的正确性:如图(图中的w1、w2是指边的编号而非上文说的w2 w1),r1,r2是st路径上必经的两边,而w1、w2……则是一些不会出现在st路径上的边,不妨假定r2的边权比任何一条wi都大。若r1<任意wi,则枚举wi边之前会先枚举r1,最小值w[r1]在路径上,又最大值w[r2]一定在路径上(因为加入该边使得st连通),我们就保证了w[r2]/w[r1]有意义。之后在枚举wi边时,因为不允许选取r1,所以无论如何也无法让st连通,故不会产生无意义解;若r1并不小于所有wi,假定w1是wi中边权最小的边,按照算法,我们会先选择w1,并得到一个解w[r2]/w[w1],这是无意义的,w1并不在路径上。然而,在之后的某个时刻我们将枚举到r1,并得到另一个解w[r2]/w[r1],因为w[r1]>w[w1],所以w[r2]/w[r1]

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.m或d论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值