算法训练营:道路升级

问题描述

Z国有 n 个城市和 m 条双向道路,每条道路连接了两个不同的城市,保证所有城市之间都可以通过这些道路互达。每条道路都有一个载重量限制,这限制了通过这条道路的货车最大的载重量。道路的编号从 1 至 m 。巧合的是,所有道路的载重量限制恰好都与其编号相同。

现在,要挑选出若干条道路,将它们升级成高速公路,并满足如下要求:

  • 所有城市之间都可以通过高速公路互达。
  • 对于任意两个城市 u,v 和足够聪明的货车司机:只经过高速公路从 u 到达 v 能够装载货物的最大重量,与经过任意道路从 u 到达 v 能够装载货物的最大重量相等。(足够聪明的司机只关注载重量,并不在意绕路)

在上面的前提下,要求选出的道路数目尽可能少。

求需要挑选出哪些道路升级成高速公路(如果有多种方案请任意输出一种)。

输入

第一行 2 个用空格隔开的整数 n,m ,分别表示城市数目、道路数目。

第 2 行到第 m+1 行,每行 2 个用空格隔开的整数 u,v 描述一条从 u 到 v 的双向道路,第 i+1 行的道路的编号为 i 。

注意:数据只保证不存在连接的城市相同的道路(自环),并不保证不存在两条完全相同的边(重边)

输出

第一行一个整数 k ,表示升级成高速公路的道路数。

接下来 k 行每行一个整数,从小到大输出所有选出的道路的编号。

输入样例

5 3
1
3
5
10
3

输出样例

2
2
3

数据范围

对于 20% 的数据,保证 n≤5,m≤10。

对于 60% 的数据,保证 n≤1,000,m≤5,000。

对于 100% 的数据,保证 n≤200,000,m≤400,000。

时间限制:10 sec

空间限制:256 MB

提示

[提示1:真的可能有多种方案吗?]

[提示2:k 是否一定为 n-1 呢?(也就是说,选出的道路是否恰好构成了一棵树?)]

[提示3:这道题和最小生成树有什么关系呢?]

代码实现:

 1 #include <iostream>
 2 #include <vector>
 3 using namespace std;
 4
 5 // ================= 代码实现开始 =================
 6
 7 const int N = 500005 ;
 8
 9 class UnionSet{
10 public:
11     int f[N] ;
12     //初始化
13     //n :节点数量
14     void init( int n )
15     {
16         for( int i = 1 ; i <= n ; i++ )
17             f[i] = i ;
18     }
19     int find( int x )
20     {
21         return f[x] == x ? x : f[x] = find( f[x] ) ;
22     }
23     //将x节点和y节点所在集合合并
24     // x:一个节点
25     // y : 一个结点
26     //返回值: 返回true表示成功合并,返回false表示已经在一个集合里了
27     bool merge( int x , int y )
28     {
29         int setX = find(x) ;
30         int setY = find(y) ;
31         if( setX != setY )
32         {
33             f[setX] = setY ;
34             return true ;
35         }
36         return false ;
37     }
38 }us;
39
40 // 给定一个n个点m条边的无向图,第i条边边权为i,求所有需要升级的边
41 // n:点->城市
42 // m:边->道路
43 // U:大小为m的数组,表示m条边的其中一个端点
44 // V:大小为m的数组,表示m条边的另一个端点
45 // 返回值:所有需要升级的边,从小到大排列;第一小问的答案自然即为返回值的size,所以你不必考虑如何返回size
46
47 vector<int>getAnswer(int n, int m, vector<int> U, vector<int> V)
48 {
49     vector<int> ans;
50     us.init(n);
51     //构造最大生成树,找权值最大的边
52     for( int i = m - 1 ;  i >= 0 ;  --i )
53         if( us.merge( U[i] , V[i] ) )
54             ans.push_back( i + 1 ) ;         //加入边,从1开始到m
55     reverse(ans.begin() , ans.end());            //原来ans试从小到大排列的,现将ans数组从大到小排列
56     return ans;
57 }
58
59 int main()
60 {
61     int n, m;
62     scanf("%d%d", &n, &m);
63     vector<int> U, V;
64     for (int i = 0; i < m; ++i) {
65         int u, v;
66         scanf("%d%d", &u, &v);
67         U.push_back(u);
68         V.push_back(v);
69     }
70     vector<int> ans = getAnswer(n, m, U, V);
71     printf("%d\n", int(ans.size()));
72     for (int i = 0; i < int(ans.size()); ++i)
73         printf("%d\n", ans[i]);
74     return 0;
75 }

原文地址:https://www.cnblogs.com/syyyyy/p/10350863.html

时间: 2024-10-08 16:04:26

算法训练营:道路升级的相关文章

图论 - 最小生成树 - Kurskal算法 - 道路升级

问题描述 Z国有 n 个城市和 m 条双向道路,每条道路连接了两个不同的城市,保证所有城市之间都可以通过这些道路互达.每条道路都有一个载重量限制,这限制了通过这条道路的货车最大的载重量.道路的编号从 1 至 m .巧合的是,所有道路的载重量限制恰好都与其编号相同. 现在,要挑选出若干条道路,将它们升级成高速公路,并满足如下要求: 所有城市之间都可以通过高速公路互达. 对于任意两个城市 u,v 和足够聪明的货车司机:只经过高速公路从 u 到达 v 能够装载货物的最大重量,与经过任意道路从 u 到达

蓝桥杯 算法提高 道路和航路 满分AC ,SPFA算法的SLF优化,测试数据还是比较水的,貌似没有重边

算法提高 道路和航路 时间限制:1.0s   内存限制:256.0MB 问题描述 农夫约翰正在针对一个新区域的牛奶配送合同进行研究.他打算分发牛奶到T个城镇(标号为1..T),这些城镇通过R条标号为(1..R)的道路和P条标号为(1..P)的航路相连. 每一条公路i或者航路i表示成连接城镇Ai(1<=A_i<=T)和Bi(1<=Bi<=T)代价为Ci.每一条公路,Ci的范围为0<=Ci<=10,000:由于奇怪的运营策略,每一条航路的Ci可能为负的,也就是-10,000

【BZOJ 1579】 1579: [Usaco2009 Feb]Revamping Trails 道路升级 (最短路)

1579: [Usaco2009 Feb]Revamping Trails 道路升级 Description 每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M<=50,000)条双向泥土道路,编号为1..M. 道路i连接牛棚P1_i和P2_i (1 <= P1_i <= N; 1 <= P2_i<= N). John需要T_i (1 <= T_i <= 1,000,000)时间单位用道路i从P1_i走到P2_i或者从P2_i 走

Bzoj 1579: [Usaco2009 Feb]Revamping Trails 道路升级 dijkstra,堆,分层图

1579: [Usaco2009 Feb]Revamping Trails 道路升级 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1573  Solved: 428[Submit][Status][Discuss] Description 每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M<=50,000)条双向泥土道路,编号为1..M. 道路i连接牛棚P1_i和P2_i (1 <= P1_i <= N;

BZOJ 1579: [Usaco2009 Feb]Revamping Trails 道路升级( 最短路 )

最短路...多加一维表示更新了多少条路 ---------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<queue> #include<cstring> #include<iostream> #define rep( i , n ) for( int i

算法笔记_165:算法提高 道路和航路(Java)

目录 1 问题描述 2解决方案   1 问题描述 问题描述 农夫约翰正在针对一个新区域的牛奶配送合同进行研究.他打算分发牛奶到T个城镇(标号为1..T),这些城镇通过R条标号为(1..R)的道路和P条标号为(1..P)的航路相连. 每一条公路i或者航路i表示成连接城镇Ai(1<=A_i<=T)和Bi(1<=Bi<=T)代价为Ci.每一条公路,Ci的范围为0<=Ci<=10,000:由于奇怪的运营策略,每一条航路的Ci可能为负的,也就是-10,000<=Ci<

bzoj 1579: [Usaco2009 Feb]Revamping Trails 道路升级 优先队列+dij

1579: [Usaco2009 Feb]Revamping Trails 道路升级 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1768  Solved: 481[Submit][Status][Discuss] Description 每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M<=50,000)条双向泥土道路,编号为1..M. 道路i连接牛棚P1_i和P2_i (1 <= P1_i <= N;

bzoj 1579: [Usaco2009 Feb]Revamping Trails 道路升级 -- 分层图最短路

1579: [Usaco2009 Feb]Revamping Trails 道路升级 Time Limit: 10 Sec  Memory Limit: 64 MB Description 每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M<=50,000)条双向泥土道路,编号为1..M. 道路i连接牛棚P1_i和P2_i (1 <= P1_i <= N; 1 <= P2_i<= N). John需要T_i (1 <= T_i <

【bzoj1579/Usaco2009 Feb】Revamping Trails 道路升级——分层图最短路

题目链接 建立0~k共k+1层图,用dis[x][d]表示x到源点(此题为1)将d条道路距离降为0的距离,dijkstra跑的话因为从堆顶取出的就是已经确定的,因此当从堆顶取出的元素是n时,就可以直接返回并输出了. 用了堆优化,注意每次从堆顶取出元素后如果p.w!=dis[p.to][p.d],说明这条路径所到达的点到源点的路径已经被其他路径所松弛,换句话说,此时1~x走的根本不是存的这条路径,所以要重新从堆顶取满足条件的元素. 1 #include<cstdio> 2 #include<