CCF-CSP 201509-4高速公路

9 篇文章 0 订阅
2 篇文章 0 订阅

题目:
http://118.190.20.162/view.page?gpid=T29
算法
Tarjan算法,这是讲的还不错的一篇:https://blog.csdn.net/qq_34374664/article/details/77488976
总的来说,就是将强连通分量当做一棵树去处理,到最后能找出这棵树的根节点,就找到一条强连通分量。
对low[]可以这样理解
LOW[ i ] : 为i或i的子树能够追溯到的最早的栈中节点的次序号

细节
记得把每个节点都走一遍,防止有漏掉的。

代码:

#include<bits/stdc++.h>
using namespace std;

const int MAX = 10005; //自己设定MAX最合适

vector<int>graph[MAX]; //存储有向图

//index[i]表示i是第几个被访问的结点,lowLink[i]表示从i出发经有向边可到达的所有结点最小的index,sccno[i]表示i所属的强连通分量的编号 
int index[MAX], lowLink[MAX],sccno[MAX],dfsNo = 0,scc_cnt = 0;

int ans = 0; //最终结果

stack<int>s;

//基于DFS的tarjan算法 
void  DFS(int v){
	index[v] = lowLink[v] = ++dfsNo;
	s.push(v);
	for(int i:graph[v]){
		if(index[i]==0){
			DFS(i);
			lowLink[v] = min(lowLink[i],lowLink[v]);
		}else if(sccno[i]==0){ //已被访问过但i还未出栈
			lowLink[v] = min(lowLink[v],index[i]);
		}
	}
	
	if(lowLink[v]==index[v]){
	 //是一个强连通分支的根节点 
	 ++scc_cnt; //强连通分支的编号
	 int t, num = 0; //num表示该强连通分支的节点的个数
	 do{
	 	t = s.top();
	 	s.pop();
	 	++num;
	 	sccno[t] = scc_cnt;
	 } while(t!=v) //当t==v,栈就到头了
	 ans += (num-1)*num/2; //加上该强连通分支的便利城市对个数 
}
int main(){
	int n,m,k,a,b;
	scanf("%d%d",&n,&m); //不需要空格
	while(m--){
		scanf("%d%d",&a,&b);
		graph[a].push_back(b);
	} 
	for(int i = 1;i<=n;++i){
		//为了防止有漏网之鱼,就从把每个结点都搞一遍,如果这个结点已经被搞过一遍了,即index[i]!=0 
		if(index[i]==0){
			DFS(i); 
		}
	}
	printf("%d",ans);
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值