フェイス質問
https://www.luogu.org/problem/P3731
問題の解決策
カッティングエッジを求めることは二部グラフとすることができます。
#include <キュー> の#include <スタック> の#include <ベクトル> の#include <cstdioを> する#include <ユーティリティ> の#include <CStringの> する#include <iostreamの> する#include <アルゴリズム> の#define N 10050 の#define M 150050 の#define INF 1000000007 の#define S 0 の#define T(N + 1) の#define LL長い長 の#define intを登録RI 使用して 名前空間STDを、 INTのN、M、U [M]、V [M]。 ベクター < INT > 乃至[N]。 int型COL [N]、DFN [N]。 対 < INT、INT > ANS [M]。 インラインint型リード(){ int型 RET = 0、F = 0。チャー CH = GETCHAR()。 一方、(CH < ' 0 ' || CH> ' 9 ')は、f | =(CH == ' - ')、CH = GETCHAR()。 一方、(CH> = ' 0 ' && CH <= ' 9 ')RET * = 10、RET + =(CH- ' 0 ')、CH = GETCHAR()。 リターン F - ?RET:RET; } 構造体グラフ{ ベクトル < INT > ED [N]。 ベクトル < 整数 > に、ワット。 INT D [N]、CUR [N]。 INT ベル[N]、DFN [N]、低[N]、CC、CNT。 ブールイン[N]。 スタック < 整数 > STK。 ボイド add_edge(int型 U、int型 V、int型TW){ to.push_back(V)。w.push_back(TW)。ED [U] .push_back(to.size()- 1 )。 to.push_back(U); w.push_back( 0)。ED [V] .push_back(to.size() - 1 )。 } BOOL BFS(){ キュー < INT > Q。 memsetの(D、0x3fを、はsizeof (d)参照)。 D [S] = 0 ; q.push(S)。 一方、(!q.empty()){ int型のx = q.front()。q.pop(); 用(RI i = 0 ; iが編<[X] .size(); iは++ ){ int型、E = ED [X] [I]; もし(D [X] + 1 <D [乃至[E] && W [E]){ D [乃至[E] = D [X] + 1 。 ([E]に)q.push。 } } } 戻り D [T] < INF。 } INT DFS(int型のx、int型の制限){ 場合(X == T ||限界== 0)リターンリミット。 int型の合計= 0 ; 用(RI&I = CUR [X]; iは<ED [X] .size(); iは++ ){ int型、E = ED [X] [I]; もし(W [E] && D [X] + 1 ==のD [乃至[E]]){ int型 F =DFS([E]、分(限界に、W [E]))。 もし(!f)を続けます。 和 + = F。リミット-側= F。 W [E] - = F。[W 1 ^ E] + = F。 もし(!リミット)リターン合計。 } } 戻り値の和。 } int型dinic(){ int型 RET = 0 。 一方、(BFS()){ memsetの(CUR、0、はsizeof (CUR))。 RET + = DFS(S、INF)。 } 戻りRET。 } のボイド tarjan(INT X){ [X] DFN =低[X] = ++CC; イン[X] = 1 。stk.push(X)。 用(RI i = 0 ; iが編<[X] .size(); iは++ ){ int型、E = ED [X] [I]; もし(![E]ワット)続けます。 もし(DFN [乃至[E]]){ 場合(INS [乃至[E])低[X] = 分(低[x]は、DFN [乃至[E])。 } 他{ ([E]に)tarjan。 低[X] = 分(低[x]は、低[乃至[E])。 } } もし(DFN [X] == 低[X]){ int型の {トン; ++ CNT; DO トン = stk.top(); stk.pop(); イン[T] = 0 ; ベル[T] = CNT。 } 一方、(T =!X)。 } } } G。 ボイド DFS(int型のx、int型の){ DFN [X] = 1。COL [X] =のS。 用(RI i = 0 ; iが<[X] .size(); iは++ ){ int型、Y = に[X] [I]; もし(!DFN [Y])DFS(Y、S ^ 1 )。 } } int型{main()の N)=(読み取り; M = 読み取ります(); にとって(RI I = 1 ; I <= M; iが++ ){ uは[I] =(読み取り)V [I] = (読み取り) [U [I]一back(V [i])とします。[V [I]一back(U [i])とします。 } のための(RI i = 1 ; iが<= N; iが++)場合(!DFN [i])とDFS(I、0 ); 用(RI i = 1 ; I <= M; iは++ ){ 場合(COL [U [I])G.add_edge(U [i]は、V [i]は、1)。他 G.add_edge(V [i]は、U [i]は、1 )。 } のための(RI i = 1 ; I <= N; iは++)場合(COL [i])とG.add_edge(S、I、1); 他G.add_edge(I、T、1 ); G.dinic(); 用(RI i = 1 ; iが++; iが<= n)の場合(!G.dfn [i])とG.tarjan(I)。 int型 CC = 0 ; 用(RI i = 0 ; iはGwsizeを()<I + = 2 ){ 場合(G.bel [G.to [I ^ 1!] = G.bel [G.to [I]] && G.to [I ^ 1 ]> = 1 && G.to [I ^ 1 ] <= N && G.to [I]> = 1 && G.to [I] <= N &&!GWは、[I]){ ANS [ ++ CC = make_pair(MIN(G.to [I ^ 1 ]、G.to [i])と、MAX(G.to [I ^ 1 ]、G.to [I]))。 } } ソート(ANS + 1、ANS + CC + 1 )。 printf(" %d個の\ n " 、CC)。 用(RI I = 1のprintf(; iが= CCを<I ++)は、 " %D%D \ n " 、ANS [i]が1次回、ANS [I] .second)。 リターン 0 ; }