说在前面
其实me博客里有一篇文章把割点桥,强连通双连通的板子都总结了一遍。这道题…核心算法直接贴板子就可以过了的。
本来没有写这个题解的打算,然而真是服了这谜一样的题面和读入方式,最终me决定还是写一点什么,比如题面的翻译和输入解释….
题面
题意
给你一张图,节点数小于100个,保证图联通。询问这张图里有多少割点
输入
多组测试数据
对于每组测试数据的第一行,输入一个整数N,表示一共有N个节点
接下来若干行,每行第一个数字u,接下来一些数字vi,表示u和vi之间有边,每行以回车符结尾。
每组测试数据以u==0结尾
整个输入以N==0结尾
输出
每组测试数据一行,表示割点个数
题解
这题,数据规模小到一定境界(毕竟是96年的题),随便乱搞都可以。
最暴力的做法比如:直接枚举每个点是不是割点。
正常一点的做法比如:tarjan求割点。
看个人喜好。直接上代码吧。
自带大常数的代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N , head[105] , tp , cnt ;
class Path{
public :
int pre , to ;
}p[100005] ;
void In( int t1 , int t2 ){
p[++tp].pre = head[t1] ;
p[ head[t1] = tp ].to = t2 ;
}
int dfn[105] , dfs_c ;
bool iscut[105] ;
int dfs( int u , int f ){
int lowu = dfn[u] = ++dfs_c , child = 0 ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == f ) continue ;
if( !dfn[v] ){
child ++ ;
int lowv = dfs( v , u ) ;
lowu = min( lowv , lowu ) ;
if( lowv >= dfn[u] )
iscut[u] = true ;
} else lowu = min( dfn[v] , lowu ) ;
}
if( f == -1 && child == 1 ) iscut[u] = false ;
return lowu ;
}
void clear(){
cnt = dfs_c = tp = 0 ;
memset( dfn , 0 , sizeof( dfn ) ) ;
memset( head , 0 , sizeof( head ) ) ;
memset( iscut , 0 , sizeof( iscut ) ) ;
}
int main(){
int u , v ;
while( scanf( "%d" , &N ) && N ){
clear() ;
while( scanf( "%d" , &u ) && u ){
while( 1 ){
scanf( "%d" , &v ) ;
In( u , v ) ;
In( v , u ) ;
if( getchar() == '\n' ) break ;
}
}
dfs( 1 , -1 ) ;
for( int i = 1 ; i <= N ; i ++ )
if( iscut[i] ) cnt ++ ;
printf( "%d\n" , cnt ) ;
}
}