[题解]codevs1001 舒适的路线
题目描述 Description
Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光。Z小镇附近共有N(1<N≤500)个景点(编号为1,2,3,…,N),这些景点被M(0<M≤5000)条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路。也许是为了保护该地的旅游资源,Z小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi。频繁的改变速度使得游客们很不舒服,因此大家从一个景点前往另一个景点的时候,都希望选择行使过程中最大速度和最小速度的比尽可能小的路线,也就是所谓最舒适的路线。
输入描述 Input Description
第一行包含两个正整数,N和M。
接下来的M行每行包含三个正整数:x,y和v(1≤x,y≤N,0 最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速度比最小的路径。s和t不可能相同。
输出描述 Output Description
如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一个既约分数。
样例输入 Sample Input
样例1
4 2
1 2 1
3 4 2
1 4
样例2
3 3
1 2 10
1 2 5
2 3 8
1 3
样例3
3 2
1 2 2
2 3 4
1 3
样例输出 Sample Output
样例1
IMPOSSIBLE
样例2
5/4
样例3
2
数据范围及提示 Data Size & Hint
N(1<N≤500)
M(0<M≤5000)
Vi在int范围内
(转自[codevs1001])
最开始(大概半年前吧),这道题也没想出来,直接去spfa,写到一半,发现有问题,一个点最大限速比最小限速最小,不能保证后面的点也是最小。
然后看题解,看了几个,都没看懂,只是知道了一件事,要用并查集。
现在重新来看这道题。通过并查集想到了最小(大)生成树。按照最大生成树来做,直到s和t连通。连通后可以发现当经过这条路上最大限速的这一条边的情况是最优的(因为这条路径上每一条边都尽可能大),但是不是整张图中最优的。怎么办?多算几条很优的线。把这条路径最大限速的那条边删掉(因为再保留这条边已经没有意义了,对于这条边来说已经是最优的了),更新答案,重新最大生成树。直到无论怎么加边s,t都不会连通的时候退出算法。
(貌似用最小生成树也行,不过删的那条边变成了最小限速),算法时间复杂度大概是O(m2 + mn)(生成树上dfs,时间复杂度$O(n)$)
Code(超级不简洁的代码,其中前134行是模板,主要过程在167行以后)
- /**
- * codevs.cn
- * Problem1001
- * Accepted
- * Time:378ms
- * Memory:588k
- */
- #include<iostream>
- #include<sstream>
- #include<cstdio>
- #include<cmath>
- #include<cstdlib>
- #include<cstring>
- #include<cctype>
- #include<ctime>
- #include<queue>
- #include<set>
- #include<map>
- #include<stack>
- #include<vector>
- #include<algorithm>
- using namespace std;
- typedef bool boolean;
- #define smin(a, b) (a) = min((a), (b))
- #define smax(a, b) (a) = max((a), (b))
- template<typename T>
- inline void readInteger(T& u){
- char x;
- int aFlag = ;
- while(!isdigit((x = getchar())) && x != '-');
- if(x == '-'){
- aFlag = -;
- x = getchar();
- }
- for(u = x - ''; isdigit((x = getchar())); u = u * + x - '');
- ungetc(x, stdin);
- u *= aFlag;
- }
- typedef class union_found{
- public:
- int points;
- int *f;
- union_found():f(NULL) {}
- union_found(int points):points(points){
- f = new int[(const int)(points + )];
- for(int i = ; i <= points; i++)
- f[i] = i;
- }
- int find(int x) {
- if(f[x] != x) return f[x] = find(f[x]);
- return f[x];
- }
- void unit(int fa, int so) {
- int ffa = find(fa);
- int fso = find(so);
- f[fso] = ffa;
- }
- boolean connected(int a, int b) {
- return find(a) == find(b);
- }
- void clean(){
- for(int i = ; i <= points; i++)
- f[i] = i;
- }
- }union_found;
- ///map template starts
- typedef class Edge{
- public:
- int end;
- int next;
- int w;
- int id;
- Edge(const int end = , const int next = , const int w = , const int id = ):end(end), next(next), w(w), id(id){}
- }Edge;
- typedef class MapManager{
- public:
- int ce;
- int *h;
- Edge *edge;
- MapManager(){}
- MapManager(int points, int limit):ce(){
- h = new int[(const int)(points + )];
- edge = new Edge[(const int)(limit + )];
- memset(h, , sizeof(int) * (points + ));
- }
- inline void addEdge(int from, int end, int w, int id){
- edge[++ce] = Edge(end, h[from], w, id);
- h[from] = ce;
- }
- inline void addDoubleEdge(int from, int end, int w, int id){
- addEdge(from, end, w, id);
- addEdge(end, from, w, id);
- }
- inline void clean(){
- delete[] h;
- delete[] edge;
- ce = ;
- }
- }MapManager;
- #define m_begin(g, i) (g).h[(i)]
- #define m_end(g, i) (g).edge[(i)].end
- #define m_next(g, i) (g).edge[(i)].next
- #define m_w(g, i) (g).edge[(i)].w
- ///map template ends
- typedef class Fraction{
- public:
- int s;
- int m;
- Fraction():s(),m(){}
- Fraction(int s,int m){
- int g = getCommon(s, m);
- this->s = s / g;
- this->m = m / g;
- }
- boolean empty(){
- return m == ;
- }
- boolean operator <(Fraction another) const{
- if(another.empty()) return true;
- if(m == ) return false;
- if(this->s == another.s) return this->m>another.m;
- return (this->s * 1.0 / this->m) < (another.s * 1.0 / another.m);
- }
- private:
- int getCommon(int a, int b){
- if(b == ) return a;
- return getCommon(b, a % b);
- }
- }Fraction;
- typedef class Edge1{
- public:
- int end;
- int from;
- int w;
- Edge1(const int end = , const int from = , const int w = ):end(end), from(from), w(w){}
- }Edge1;
- int n, m;
- Edge1* edge;
- union_found uf;
- MapManager g;
- int s, t;
- inline boolean cmpare(const Edge1& a, const Edge1& b){
- return a.w > b.w;
- }
- inline void init(){
- readInteger(n);
- readInteger(m);
- edge = new Edge1[(const int)(m + )];
- for(int i = ; i <= m; i++){
- readInteger(edge[i].from);
- readInteger(edge[i].end);
- readInteger(edge[i].w);
- }
- readInteger(s);
- readInteger(t);
- }
- int minl, maxl, maxide;
- void dfs(int minv, int maxv, int maxid, int last, int node){
- if(node == t){
- minl = minv, maxl = maxv, maxide = maxid;
- return;
- }
- for(int i = m_begin(g, node); i != ; i = m_next(g, i)){
- int& e = m_end(g, i);
- if(e == last) continue;
- int nmin = min(minv, m_w(g, i));
- int nmax = max(maxv, m_w(g, i));
- int nid = (nmax == m_w(g, i)) ? (g.edge[i].id) : (maxid);
- dfs(nmin, nmax, nid, node, e);
- }
- }
- boolean *enable;
- Fraction result;
- inline void solve(){
- sort(edge + , edge + m + , cmpare);
- enable = new boolean[(const int)(m + )];
- memset(enable, true, sizeof(boolean) * (m + ));
- uf = union_found(n);
- for(int i = ; i <= m; i++){
- int j;
- g = MapManager(n, m * );
- for(j = ; j <= m; j++){
- if(enable[j] && !uf.connected(edge[j].from, edge[j].end)){
- uf.unit(edge[j].from, edge[j].end);
- g.addDoubleEdge(edge[j].from, edge[j].end, edge[j].w, j);
- if(uf.connected(s, t)){
- maxide = -;
- dfs(0x7fffffff, -, -, , s);
- uf.clean();
- g.clean();
- break;
- }
- }
- }
- if(j == m + ) break;
- else{
- smin(result, Fraction(maxl, minl));
- enable[maxide] = false;
- }
- }
- if(result.empty()) printf("IMPOSSIBLE");
- else if(result.m != ) printf("%d/%d", result.s, result.m);
- else printf("%d", result.s);
- }
- int main(){
- init();
- solve();
- return ;
- }
后话
最后加的那一条边是最小的限速,可以倒推,得到一条边使s, t连通,后者是最大的限速。还有个方法优化,把没有的边去掉,而不是一次一次地删最大的那条边,详见[传送门]
[题解]codevs1001 舒适的路线的更多相关文章
- [codevs1001]舒适的路线
[codevs1001]舒适的路线 试题描述 Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光.Z小镇附近共有N(1<N≤500)个景点(编号为1,2,3,-,N),这些景点被M(0 ...
- codevs1001 舒适的路线 - 贪心 - 并查集
题目描述 Description Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光.Z小镇附近共有N(1<N≤500)个景点(编号为1,2,3,…,N),这些景点被M(0<M≤ ...
- CODEVS1001 舒适的路线 (并查集)
对所有边从大到小排序,枚举最大边,O(m)验证,用并查集维护图是否联通. program CODEVS1001; ; maxn=; INF=; type arr=record u,v,w:int64; ...
- 【Kruskal】舒适的路线
[codevs1001]舒适的路线 题目描述 Description Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光.Z小镇附近共有N(1<N≤500)个景点(编号为1,2,3,… ...
- 求最大边/最小边的比值最小的路径 codevs 1001 舒适的路线
codevs 1001 舒适的路线 2006年 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Z小镇是一个景色宜人 ...
- AC日记——舒适的路线 codevs 1001 (并查集+乱搞)
1001 舒适的路线 2006年 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description Z小镇是 ...
- codevs 1001 舒适的路线(Kruskal)
传送门 Description Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光.Z小镇附近共有N(1<N≤500)个景点(编号为1,2,3,…,N),这些景点被M(0<M≤5 ...
- Codevs 1001 舒适的路线 2006年 NOIP全国联赛提高组
1001 舒适的路线 2006年 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Z小镇是一个景色宜人的地方,吸引来自各地的观 ...
- codevs 1001 舒适的路线 (并查集)
题目描述 Description Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光. Z小镇附近共有 N(<N≤)个景点(编号为1,,,…,N),这些景点被M(<M≤)条道路连 ...
随机推荐
- mysql事务和并发控制
谈到事务,首先想到的问题是并发控制.比如两个用户同时操作数据库里面的一张表,一个正在读数据,一个正在删除数据,那么读数据的读出的结果究竟是多少?并发可以提高系统的性能,让多个用户同时操作一份数据,但为 ...
- TCP\IP三次握手连接,四次握手断开分析
TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标 ...
- js原型基础
js中的原型链是实现继承等面向对象的一种方式,而我这里不详细展开,仅仅是画了一张原型部分结构图,主要说明: 1._proto_和prototype之间的关系 2.原型链的起点是Object.proto ...
- python模块之subprocess
可以执行shell命令的相关模块和函数有: os.system os.spawn* os.popen* --废弃 popen2.* --废弃 commands.* ...
- 移动端自动化环境搭建-Appium Client的安装和AppiumLibrary库的安装
A.安装依赖 appium client是配合原生的webdriver来使用的(特别是用java而不用maven的同学),因此二者必须配合使用缺一不可. B.安装过程 1.在线安装 pip insta ...
- html5 弹框 可用于安卓手机弹出输入框
function text() { name=prompt("请输入wifi密码"); // 弹出input框 prompt('提示语','默认输入框字段') //alert(na ...
- EBS中配置OAF
配置EBS的OAF作者 redqq 16:09 | 静态链接网址 | 最新回复 (0) | 引用 (0) | ERP学习 载jdev 9.03.5带Oracle Applications Extens ...
- NSJSONSerialization 组json字符串
抄的网上的. 主要是组织列表部分 NSDictionary *song = [NSDictionary dictionaryWithObjectsAndKeys:",@"lengt ...
- 关于已配置log4j,运行tomcat时显示警告的分析
有时候,我们在JavaEE项目中配置了log4j及其参数信息,但是启动tomcat时,仍会显示如下信息:
- centos6配置网卡
#设置开机启动和静态地址 vi /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 HWADDR=D8::E6::3F:CF TYPE=Ethe ...