する#include <stdio.hに> する#include <アルゴリズム> の#include <iostreamの> する#include < 文字列・H> 使用して 名前空間STD; / * *切削点への要求と、図のブリッジ *カットポイントを見つけることができないとブリッジは、シークブロック通信削除各点が増加した後。 *重いエッジの処理は、第1の行列を格納することができることを、隣接するサブテーブル、または再調停注 * / CONST INT MAXN = 10010 ; のconst int型 MAXM = 100010 ; 構造体のエッジ { INT に、次に、 BOOL切り取り; // かどうかのフラグブリッジ }エッジ[MAXM]; int型のヘッド[MAXN]、TOT、 INT低[MAXN]、DFN [MAXN]、スタック[MAXN]; int型、インデックス、トップ BOOL Instack [MAXN]; BOOL カット[MAXN]; int型 add_block [MAXN]; //は、通信ポイントブロック取り除いた後に追加 int型の橋を; ボイド addedge(INT U、int型V) { エッジ[TOT] .TO = V、エッジ[TOT】ヘッド.next = [U]、エッジ[TOT = .cut falseに、 ヘッド[U] = TOT ++ ; } ボイド Tarjan(INT U、INT PRE) { int型のV; 低[U] = DFN [U] ++ = ++] =ランキング; スタック[トップU; Instack [U] = 真。 int型の息子= 0 ; 以下のために(int型 - ;!I = I =ヘッド[U] 1 ; I = エッジ[I] .next) { V = エッジ[I] .TO。 もし(V ==前)続けます。 もし(!DFN [V]) { 息子 ++ ; Tarjan(V、U); もし(低[U]>低[V])低[U] = 低[V]。 // 桥 //無向エッジと場合にのみ、(u、v)は側枝であり、そしてDFS(U)<低を満たす場合には(u、v)は、ブリッジである(V )。 IF(低[V]> DFN [U]) { 橋 ++ 、 エッジ[I] .cut = trueに、 エッジ[I ^ 1 ] = .cut 真に; } // カットポイント // 頂点uがカットポイントであります満足場合にのみ(1)又は(2)(1)Uがルートであり、uは、複数のサブツリーを有します。 @ (2)Uは(U、V)側枝(または親子エッジの存在満たし、ルートでない // このようなDFS(U)<=低いこと、即ち、U及び探索木におけるV父) (V) IF(U!&&事前=低[V]> = DFN [U])// ないルート { 切り取り[U]= 真、 add_block [U] ++ ; } } そう であれば(低[U]> DFN [V]) 低[U] = DFN [V]。 } // 树根、分支数大于1 た場合(Uは==事前&&息子> 1)= [U]を切断真。 もし(U == PRE)add_block [U] =息子- 1 。 Instack [U] = 偽。 トップ - ; } ボイドが解決する(INTのN) { memsetの(DFN、0、はsizeof (DFN))。 memsetの(Instack、偽、はsizeof (Instack)); memset(add_block、0、はsizeof (add_block))。 memsetの(カット、偽、はsizeof (カット)); インデックス =トップ= 0 ; ブリッジ = 0 。 以下のために(int型 I = 1 ; N =私は<;私は++ ) の場合(!DFN [i])と Tarjan(I、I); int型 ANS = 0 ; 以下のために(int型 I = 1 = iが<Nを;私++) 場合(切断[i])と ANS ++ 。 printf(" %d個の\ n " 、ANS)。 } ボイドのinit() { TOT = 0 。 memsetの(頭、 - 1、はsizeof (ヘッド))。 } int型のmain() { int型N; 一方、(scanf関数(" %のD "、&n)は、N) { int型、B、。 char型のCH; その中に(); しばらく(scanf関数(" %dの "、&A )、A) { 一方(のscanf(" %d個の%のC "、&B、&CH)) { addedge(B) addedge(B、A)。 もし(CH == ' \ n個' ) ブレーク。 } } (n)を解きます。 } 戻り 0 。 }