试题编号: | 201509-4 |
试题名称: | 高速公路 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。 输入格式 输入的第一行包含两个整数n, m,分别表示城市和单向高速公路的数量。 输出格式 输出一行,包含一个整数,表示便利城市对的数量。 样例输入 5 5 样例输出 3 样例说明
评测用例规模与约定 前30%的评测用例满足1 ≤ n ≤ 100, 1 ≤ m ≤ 1000; |
问题连接:CCF 201509-4 高速公路
题解:有向图强连通分支模板题
AC的C++代码:
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
const int N=10010;
vector<int>g[N];
stack<int>s;
bool flag[N];//标记结点是否在栈内
int dfn[N],low[N];
int index;
long long ans;
void Tarjan(int u)
{
dfn[u]=low[u]=++index;
s.push(u);
flag[u]=true;//记录结点u在栈内
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(!dfn[v]){//如果结点v没有被访问
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(flag[v])//如果v被访问并且在栈内
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){//u是一个强连通分量的根
int num=0,v;
do{
num++;
v=s.top();
s.pop();
flag[v]=false;//记录v不再栈中
}while(u!=v);//退栈,把整个强连通分量都弹出来
if(num>1)
ans+=(num-1)*num/2;
}
}
int main()
{
int n,m,a,b;
scanf("%d%d",&n,&m);
while(m--){
scanf("%d%d",&a,&b);
g[a].push_back(b);
}
for(int i=1;i<=n;i++)
if(!dfn[i])//如果结点i没有被访问
Tarjan(i);
printf("%lld\n",ans);
return 0;
}