Why did I write this question because the second question of multiple schools yesterday is graph theory, HDU 4612.
When I got the question, I knew it was a template question, but it was too weak in graph theory. The template is too watery to be found.
Although the game was finally over, the template still had a little bit of knowledge, but I still did not know about undirected graph point shrinking.
So today, I specifically searched for the undirected graph edge dual-connected component, and then learned about the scaled-down question. The contraction of this question is similar to that of yesterday. The only difference is that there is no duplicate edge, the question has a duplicate.
Let's get rid of this first, and try to contract a duplicate edge in the afternoon.
Here are some concepts. For details, go to the shenniu blog.
Edge Connectivity: the minimum number of edges that need to be deleted to make a subgraph unconnected is the edge connectivity of the graph.
Bridge (cut edge): When an edge is deleted, the graph is no longer connected, so this edge is the bridge (cut edge) of the graph ).
Edge dual-connectivity component: the subgraph with the edge connectivity degree greater than or equal to 2 is called the edge connectivity component.
Any two points in an edge connected component can have two or more links to each other.
The meaning of this question, given N points and M sides, is undirected.
Ask you to find the minimum number of sides to add. You can make the entire graph a dual-link component of the edge.
Idea: Find all edge connected components, set the number to cnt, scale the points in an edge connected component into a block, and then recreate the graph, in this way, we get a tree with cnt nodes and cnt-1 edges.
All sides of the tree are bridges.
To make the graph an edge component, you only need to connect all the leaf nodes.
The final answer is (number of leaf nodes + 1)/2.
# Include <iostream> # include <cstdio> # include <algorithm> # include <string> # include <cmath> # include <cstring> # include <queue> # include <set> # include <vector> # include <stack> # include <map> # include <iomanip> # define PI acos (-1.0) # define Max 2505 # define inf 1 <28 # define LL (x) (x <1) # define RR (x) (x <1 | 1) # define REP (I, s, t) for (int I = (s); I <= (t); ++ I) # define ll long Long # define mem (a, B) memset (a, B, sizeof (a) # define mp (a, B) make_pair (a, B) # define PII pair <int, int> using namespace std; inline void RD (int & ret) {char c; do {c = getchar ();} while (c <'0' | c> '9'); ret = c-'0'; while (c = getchar ()> = '0' & c <= '9') ret = ret * 10 + (c-'0');} int n, m; struct kdq {int e, next;} ed [111111], bridge [1111], reed [11111]; int head [1111], num, rehea D [11111], renum; int low [1111], dfn [1111]; int st [11111]; int fa [1111]; bool vis [1111]; int dp; // Number of tarjan layers int top; // stack top int bridgenum; // number of bridges int cnt; // number of connected blocks after point reduction // you can know, cnt = bridge + 1 // click it to create a new graph. Each node is a connected block and all edges are bridges. Therefore, we have the above conclusions. Void init () {mem (rehead,-1); renum = 0; mem (head,-1); num = 0; dp = 0; top = 0; bridgenum = 0; cnt = 0; mem (low, 0); mem (dfn, 0); mem (fa,-1); mem (vis, 0 );} void add (int s, int e) {ed [num]. e = e; ed [num]. next = head [s]; head [s] = num ++;} void readd (int s, int e) {reed [renum]. e = e; reed [renum]. next = rehead [s]; rehead [s] = renum ++;}/*** template: Calculate the dual-link component of the undirected graph, scale down the point, and find the bridge (Without Duplicate edges) * **/void Tarjan (int now, int faa) {dfn [now] = low [now] = dp ++; st [++ top] = now; for (int I = head [now]; ~ I; I = ed [I]. next) {int e = ed [I]. e; if (e = faa) continue; if (dfn [e] = 0) {tarjan (e, now ); if (low [e] <low [now]) low [now] = low [e]; if (low [e]> dfn [now]) {bridge [bridgenum]. e = now; // bridge [bridgenum ++]. next = e; cnt ++; do {fa [st [top] = cnt; // contraction point} while (st [top --]! = E) ;}} else if (low [now]> dfn [e]) low [now] = dfn [e] ;}} /*** re-create a graph ***/void rebuild () {for (int I = 1; I <= n; I ++) {for (int j = head [I]; ~ J; j = ed [j]. next) {readd (fa [I], fa [ed [j]. e]); readd (fa [ed [j]. e], fa [I]) ;}} int ans = 0; int root =-1; void dfs (int now, int faa) {vis [now] = 1; int sum = 0; for (int I = rehead [now]; ~ I; I = reed [I]. next) {int e = reed [I]. e; if (e = faa) continue; if (vis [e]) continue; sum ++; dfs (e, now) ;}if (! Sum) ans ++;} void solve () {ans = 0; rebuild (); dfs (root,-1); if (cnt = 1) puts ("0"); else printf ("% d \ n", (ans + 1)/2);} int main () {while (cin> n> m) {init (); while (m --) {int a, B; RD (a); RD (B ); add (a, B); add (B, a) ;}for (int I = 1; I <= n; I ++) {// You can process unconnected graphs. If connected, this loop is only performed once. If (dfn [I] = 0) {top = dp = 1; tarjan (I,-1); ++ cnt; for (int j = 1; j <= n; j ++) {// connection block of the specially processed vertex if (dfn [j] & fa [j] =-1) fa [j] = cnt, root = cnt ;}} solve () ;}return 0 ;} # include <iostream> # include <cstdio> # include <algorithm> # include <string> # include <cmath> # include <cstring> # include <queue> # include <set> # include <vector> # include <stack> # include <map> # include <iomanip> # define PI aco S (-1.0) # define Max 2505 # define inf 1 <28 # define LL (x) (x <1) # define RR (x) (x <1 | 1) # define REP (I, s, t) for (int I = (s); I <= (t); ++ I) # define ll long # define mem (a, B) memset (a, B, sizeof (a) # define mp (a, B) make_pair (a, B) # define PII pair <int, int> using namespace std; inline void RD (int & ret) {char c; do {c = getchar ();} while (c <'0' | c> '9'); ret = c-'0'; while (c = getchar ()> = '0' & c <= '9') ret = ret * 10 + (c-'0');} int n, m; struct kdq {int e, next;} ed [111111], bridge [1111], reed [11111]; int head [1111], num, rehead [11111], renum; int low [1111], dfn [1111]; int st [11111]; int fa [1111]; bool vis [1111]; int dp; // number of layers of the tarjan int top; // stack top int bridgenum; // number of bridges int cnt; // Number of Unicom blocks after point reduction // you can know, cnt = bridge + 1 // After point reduction, create a new graph. All nodes are connected to one block, and all edges are bridges. Therefore, we have the above conclusions. Void init () {mem (rehead,-1); renum = 0; mem (head,-1); num = 0; dp = 0; top = 0; bridgenum = 0; cnt = 0; mem (low, 0); mem (dfn, 0); mem (fa,-1); mem (vis, 0 );} void add (int s, int e) {ed [num]. e = e; ed [num]. next = head [s]; head [s] = num ++;} void readd (int s, int e) {reed [renum]. e = e; reed [renum]. next = rehead [s]; rehead [s] = renum ++;}/*** template: Calculate the dual-link component of the undirected graph, scale down the point, and find the bridge (Without Duplicate edges) * **/void tarjan (I Nt now, int faa) {dfn [now] = low [now] = dp ++; st [++ top] = now; for (int I = head [now]; ~ I; I = ed [I]. next) {int e = ed [I]. e; if (e = faa) continue; if (dfn [e] = 0) {tarjan (e, now ); if (low [e] <low [now]) low [now] = low [e]; if (low [e]> dfn [now]) {bridge [bridgenum]. e = now; // bridge [bridgenum ++]. next = e; cnt ++; do {fa [st [top] = cnt; // contraction point} while (st [top --]! = E) ;}} else if (low [now]> dfn [e]) low [now] = dfn [e] ;}} /*** re-create a graph ***/void rebuild () {for (int I = 1; I <= n; I ++) {for (int j = head [I]; ~ J; j = ed [j]. next) {readd (fa [I], fa [ed [j]. e]); readd (fa [ed [j]. e], fa [I]) ;}} int ans = 0; int root =-1; void dfs (int now, int faa) {vis [now] = 1; int sum = 0; for (int I = rehead [now]; ~ I; I = reed [I]. next) {int e = reed [I]. e; if (e = faa) continue; if (vis [e]) continue; sum ++; dfs (e, now) ;}if (! Sum) ans ++;} void solve () {ans = 0; rebuild (); dfs (root,-1); if (cnt = 1) puts ("0"); else printf ("% d \ n", (ans + 1)/2);} int main () {while (cin> n> m) {init (); while (m --) {int a, B; RD (a); RD (B ); add (a, B); add (B, a) ;}for (int I = 1; I <= n; I ++) {// You can process unconnected graphs. If connected, this loop is only performed once. If (dfn [I] = 0) {top = dp = 1; tarjan (I,-1); ++ cnt; for (int j = 1; j <= n; j ++) {// connection block of the specially processed vertex if (dfn [j] & fa [j] =-1) fa [j] = cnt, root = cnt ;}} solve () ;}return 0 ;}