题目描述
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 ;
}