CCF 高速公路 100分

小鱼儿 2023-07-12 03:34 83阅读 0赞























试题编号: 201509-4
试题名称: 高速公路
时间限制: 1.0s
内存限制: 256.0MB
问题描述:

问题描述

  某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。
  现在,大臣们帮国王拟了一个修高速公路的计划。看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能。如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对。
  国王想知道,在大臣们给他的计划中,有多少个便利城市对。

输入格式

  输入的第一行包含两个整数n, m,分别表示城市和单向高速公路的数量。
  接下来m行,每行两个整数a, b,表示城市a有一条单向的高速公路连向城市b

输出格式

  输出一行,包含一个整数,表示便利城市对的数量。

样例输入

5 5
1 2
2 3
3 4
4 2
3 5

样例输出

3

样例说明


  城市间的连接如图所示。有3个便利城市对,它们分别是(2, 3), (2, 4), (3, 4),请注意(2, 3)和(3, 2)看成同一个便利城市对。

评测用例规模与约定

  前30%的评测用例满足1 ≤ n ≤ 100, 1 ≤ m ≤ 1000;
  前60%的评测用例满足1 ≤ n ≤ 1000, 1 ≤ m ≤ 10000;
  所有评测用例满足1 ≤ n ≤ 10000, 1 ≤ m ≤ 100000。

这个题是典型的用Tarjan算法求强连通分量的题。

20200306175102279.png

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<string>
  4. #include<vector>
  5. #include<queue>
  6. #include<stack>
  7. #include<map>
  8. #include<unordered_map>
  9. #include<set>
  10. #include<sstream>
  11. using namespace std;
  12. const int MAXN = 10005;
  13. vector<int> adj[MAXN]; //邻接表
  14. int low[MAXN]; //low[u] = 5表示u节点能追溯到的最早的栈中节点的序号,初始值为自己。
  15. int dfn[MAXN] = {0}; //dfn[u] = 5表示对u节点的Tarjan函数递归是第5次
  16. bool vis[MAXN] = {false}; //vis[u] = true表示u在栈中。
  17. int index = 0;
  18. stack<int> st;
  19. int cityNum = 0; //便利城市对的数量
  20. void Tarjan(int u){
  21. low[u] = dfn[u] = ++index;
  22. st.push(u);
  23. vis[u] = true;
  24. for(int i=0;i<adj[u].size();i++){
  25. int v = adj[u][i];
  26. if(!dfn[v]){ //如果v节点还没有被访问过
  27. Tarjan(v);
  28. low[u] = min(low[u],low[v]);
  29. }else if(vis[v]){
  30. low[u] = min(low[u],dfn[v]);
  31. }
  32. }
  33. int num = 0; //记录这个强连通分量包含的节点数
  34. if(dfn[u] == low[u]){ //说明自己是强连通分量的根节点
  35. while(u != st.top()){ //开始弹栈,直到栈顶元素是u
  36. vis[st.top()] = false;
  37. st.pop();
  38. num++;
  39. }
  40. vis[st.top()] = false;
  41. st.pop();
  42. num++; //最后把u也弹出。
  43. //因为是强连通分量,所以分量中的每两个节点都是便利城市对。用排列组合的公式得:
  44. cityNum += (num*(num-1)/2); //(num*(num-1)/2)是当前强连通分量中的便利城市对数
  45. //注意:强连通分量可能只包含一个节点,此时是没有便利城市对的,但是不需要分
  46. //情况讨论,因为num-1会变成0,相当于cityNum += 0;
  47. }
  48. }
  49. void TarjanTravel(int n){
  50. for(int i=1;i<=n;i++){
  51. if(!dfn[i])
  52. Tarjan(i);
  53. }
  54. }
  55. int main(){
  56. int n,m;
  57. int u,v;
  58. cin>>n>>m;
  59. while(m--){
  60. cin>>u>>v;
  61. adj[u].push_back(v);
  62. }
  63. TarjanTravel(n);
  64. cout<<cityNum<<endl;
  65. return 0;
  66. }

另外:这个题是有向图求强连通分量,还有一种题是无向图求双连通分量(连通块)。

这里有个例题,是洛谷上的,有兴趣的小伙伴可以看一看,题目较难,也是Tarjan算法。

题目出处:https://www.luogu.com.cn/problem/P3225

CSDN博客解析:https://blog.csdn.net/qq_36915686/article/details/104677266

发表评论

表情:
评论列表 (有 0 条评论,83人围观)

还没有评论,来说两句吧...

相关阅读

    相关 CCF 模板生成系统 100

    问题描述   成成最近在搭建一个网站,其中一些页面的部分内容来自数据库中不同的数据记录,但是页面的基本结构是相同的。例如,对于展示用户信息的页面,当用户为 Tom 时,网页的