思路:给出一张无向连通图,问至少需要添加几天边可以使得图中任何两个点有至少两天不同路径(边不重合),等价于至少添加几条边可以使得图为双连通分量-边连通。
显然已经处于某连通分量中的点之间必然存在两条不同路径,所以可以等效的把这个连通分量看成一个点来对待,这样就是缩点了,然后得到一棵树,此时推一下就知道还需要的边数=(叶子节点数 + 1)/ 2。
// #pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <algorithm> #include <iomanip> #include <sstream> #include <string> #include <stack> #include <queue> #include <deque> #include <vector> #include <map> #include <set> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <limits.h> // #define DEBUG #ifdef DEBUG #define debug(...) printf( __VA_ARGS__ ) #else #define debug(...) #endif #define MEM(x,y) memset(x, y,sizeof x) using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> ii; const int inf = 1 << 30; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; const int maxn = 5010; const int maxm = 20010; int head[maxn], nxt[maxm], pnt[maxm]; bool go[maxm]; int cnt; void addedge(int u,int v){ pnt[cnt] = v;nxt[cnt] = head[u];go[cnt] = false;head[u] = cnt++; pnt[cnt] = u;nxt[cnt] = head[v];go[cnt] = false;head[v] = cnt++; } int dfn[maxn], low[maxn], id[maxn]; bool vis[maxn]; int t; stack<int> st; int num; void Tarjan(int u,int fa){ // cout << "u = " << u << endl; dfn[u] = low[u] = t++; st.push(u); vis[u] = true; bool flag = true; for (int i = head[u];i != -1;i = nxt[i]){ if (go[i]) continue; go[i] = go[i ^ 1] = true; int v = pnt[i]; // cout << "v = " << v << endl; if (dfn[v] == -1){ // go[i] = go[i^1] = true; // printf("(%d, %d)\n",u, v); Tarjan(v, u); low[u] = min(low[v], low[u]); } else if (low[u] > dfn[v] && vis[v]){ low[u] = dfn[v]; } } // printf("low[%d] = %d,dfn[%d] = %d\n",u, low[u], u, dfn[u]); if (low[u] == dfn[u]){ // printf("***(%d)***\n", u); while(true){ int v = st.top(); st.pop(); vis[v] = false; id[v] = num; if (v == u) break; } num++; } } int in[maxn]; void Read(){ int n, m; scanf("%d%d",&n,&m); cnt = num = t = 0; MEM(head, -1); MEM(dfn, -1); MEM(low, -1); MEM(vis, false); while(!st.empty()) st.pop(); for (int i = 1, a ,b;i <= m;++i){ scanf("%d%d",&a, &b); addedge(a, b); // addedge(b, a); } for (int i = 1;i <= n;++i) if (dfn[i] == -1) Tarjan(i, -1); // cout << "num = " << num << endl; // for (int i = 1;i <= n;++i) // cout << id[i] << ' '; // cout << endl; for (int i = 1;i <= n;i++){ for (int j = head[i];j != -1;j = nxt[j]){ int u = id[i]; int v = id[pnt[j]]; if (u != v) in[u]++,in[v]++; } } cnt = 0; for (int i = 0;i < num;++i) if (in[i] == 2) cnt++; printf("%d\n",(cnt + 1) / 2); } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); Read(); return 0; }