「一本通 3.6 练习 3」旅游航道

题目描述

SGOI 旅游局在 SG-III 星团开设了旅游业务,每天有数以万计的地球人来这里观光,包括联合国秘书长,各国总统和 SGOI 总局局长等。旅游线路四通八达,每天都有众多的载客太空飞船在星团的星球之间来往穿梭,他们保证了任意两个星球之间总是可以通过航道到达。

但是,最近由于财政出现了困难,一些太空飞船也过于古老,又没有足够的资金购买新产品,所有只好取消一些航道。如果某一条航道的删除使得一些星球不能到达,那么这条航道是不能删除的,称之为「主要航道」。

SGOI 旅游局局长希望知道主要航道的数目,但是航道较多,他不能手工计算,于是,他委托你写一个程序,计算主要航道数目。

输入格式

输入文件包含若干组数据。

每组数据的首行有两个数 m,n。星球的编号从 1 到 m。

以下 n 行每行用两个整数 a,ba,b 描述一条航道的信息,表示从星球 a 到星球 b 是有航道的。数据由 SGOI 旅游局提供,你无需担心数据有错。

输入文件以一行0为结束。

输出格式

输出文件共有 C 行,第 i 行仅有一个数,表示第 i 组输入数据的主要行道数目。

样例

样例输入

2 1
1 2
0 0

样例输出

1

数据范围与提示

1≤n,m≤30000,1≤a,b≤m

 

这道题就是一道模板,统计桥的数量

桥和割点不同,要判断边,如果这条边走过就不能再走一次

直接上代码把

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std ;

inline int read() {
	int x = 0 ; char s = getchar() ;
	while ( !isdigit( s ) ) s = getchar() ;
	while (  isdigit( s ) ) x = (x<<1) + (x<<3) + s - 48 , s = getchar() ;
	return x ;
}

const int N = 3e4 + 10 ;

int n , m ;

struct edge { 
	int v , nxt ;
}e[N<<1] ; int tot , last[N] ;
inline void add ( int u , int v ) {
	e[++tot] = (edge){ v , last[u] } ;
	last[u] = tot ;
	e[++tot] = (edge){ u , last[v] } ;
	last[v] = tot ;
}

bool vis[N] , cut[N] ;

int id , dfn[N] , low[N] ;

void Tarjan( int u ) {
	dfn[u] = low[u] = ++id ;
	for ( int i = last[u] ; i != -1 ; i = e[i].nxt ) {
		int v = e[i].v ;
		if ( vis[i>>1] == 1 ) continue ;
		vis[i>>1] = 1 ; //判断这个边是否走过 
		if ( dfn[v] == 0 ) {  
			Tarjan( v ) ;
			low[u] = min ( low[u] , low[v] ) ;
			if ( dfn[u] < low[v] ) cut[i>>1] = 1 ; //如果不经过这一条边就不能到达u以前的点,说明这就是桥 
		}
		else low[u] = min ( low[u] , dfn[v] ) ;
	}
}

int main() {
	int u , v ;
	while ( cin >> n >> m && n != 0  ) {
		tot = -1 , memset ( last , -1 , sizeof( last ) ) ;
		for ( int i = 1 ; i <= m ; i ++ ) 
			u = read() , v = read() , add ( u , v ) ;
		memset ( vis , 0 , sizeof( vis ) ) ;
		memset ( cut , 0 , sizeof( cut ) ) ;
		memset ( dfn , 0 , sizeof( dfn ) ) , id = 0 ;
		memset ( low , 0 , sizeof( low ) ) ;
		Tarjan( 1 ) ; int res = 0 ; //因为整个图数联通的,所以直接从1开始Tarjan就好了 
		for ( int i = 0 ; i <= (tot>>1) ; i ++ ) 
			if ( cut[i] == 1 ) res ++ ;
		cout << res << endl ;
	}
	return 0 ; 
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值