CODEVS 1001 舒适的路线 题解
来源:互联网 发布:施耐德base 知乎 编辑:程序博客网 时间:2024/05/17 04:05
#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]
- CODEVS 1001 舒适的路线 题解
- codevs 1001 舒适的路线(并查集) 题解
- Codevs 1001 舒适的路线
- codevs 1001 舒适的路线
- Codevs 1001 舒适的路线
- codevs 1001 舒适的路线
- 【codevs 1001】舒适的路线
- codevs 1001 舒适的路线
- 【codevs 1001】舒适的路线
- CODEVS 1001舒适的路线
- codevs 舒适的路线 1001
- codevs 1001 舒适的路线
- CODEVS 1001 舒适的路线
- codevs 1001 舒适的路线
- 【codevs 1001】舒适的路线
- 【codevs 1001】 【bzoj1050】舒适的路线
- codevs 1001 舒适的路线(并查集)
- codevs 1001 舒适的路线(并查集+贪心)
- C++泛型中replace和replace_copy
- redis实现消息队列
- hdu1824 Let's go home--2-sat
- 第三周 项目四——顺序表应用(1)
- 面试笔试---C\C++查漏补缺
- CODEVS 1001 舒适的路线 题解
- 拔掉网线时Socket的检查方法
- Java Web知识点【3】
- loader的基本用法
- 单向循环队列
- Android Fragment的动态添加,Fragment,Activity以及Fragment之间的通信方式
- 10bit视频是什么?
- mysql下如何查看表
- 简单日历的制作