试题编号: | 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算法,关于tarjan算法可以阅读tarjan算法-解决有向图中求强连通分量的利器这篇文章。
不多说,上代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include "Stdafx.h" #include <iostream> #include <stack> using namespace std; #define MAX_VERTEX_SIZE 10001 struct EdgeNode{ int vertex; EdgeNode *nextArc; }; struct VerTexNode{ EdgeNode* firstArc; }; struct Graph{ int n,e; VerTexNode vNode[MAX_VERTEX_SIZE]; }; int time = 0; int low[MAX_VERTEX_SIZE]; int dfn[MAX_VERTEX_SIZE]; int visited[MAX_VERTEX_SIZE]; int inStack[MAX_VERTEX_SIZE]; int ans = 0;//存储运算结果 stack<int> st; Graph graph; void initeGraph(int n,int m) { for(int i = 1;i<=n;i++) { graph.vNode[i].firstArc = NULL; } graph.n = n; graph.e = m; } //头插法建立图 void creatGraph(int s,int v) { EdgeNode *edgeNode = new EdgeNode; edgeNode->vertex = v; edgeNode->nextArc = graph.vNode[s].firstArc; graph.vNode[s].firstArc = edgeNode; } int min(int a,int b) { if(a>b) return b; else return a; } void trajan(int u) { dfn[u] = low[u] = time++; st.push(u); visited[u] = 1; inStack[u] = 1; EdgeNode *edgePtr = graph.vNode[u].firstArc; while(edgePtr !=NULL) { int v = edgePtr->vertex; if(visited[v] == 0) { trajan(v); low[u] = min(low[u],low[v]); } /*之前没有对inStack[v]进行判断,又可能当前的v已经出栈了,这个时候就会出错。 所以导致我的最后得分为80分。 加上if条件,最后为满分。 切记!切记!切记!!! */ else if(inStack[v] == 1) { low[u] = min(low[u],dfn[v]); } edgePtr = edgePtr->nextArc; } int result = 0; if(dfn[u] == low[u]) { int vtx; //cout<<"set is: "; do{ result++; vtx = st.top(); st.pop(); inStack[vtx] = 0;//表示已经出栈 /* cout<<vtx<<' ';*/ }while(vtx !=u ); if(result > 1) { ans += result*(result-1)/2; } result = 0; } } int main() { int n,m; int s,a; cin>>n>>m; initeGraph(n,m); for(int i = 1;i<=n;i++) { visited[i] = 0; inStack[i] = 0; dfn[i] = 0; low[i] = 0; } for(int j = 1;j<=m;j++) { cin>>s>>a; creatGraph(s,a); } for(int i =1;i<=n;i++) if(visited[i] == 0) trajan(i); cout<<ans<<endl; return 0; }
写代码是一种艺术,甚于蒙娜丽莎的微笑。