[USACO06JAN]冗餘路徑Redundant Paths --- 邊-雙聯通分量 + 縮點
阿新 • • 發佈:2018-11-10
**傳送門:**洛谷P2860
題目大意
給出一張無向圖(保證聯通),問至少新增多少條邊使得整個圖為邊雙聯通圖(即不存在橋)
分析
首先求出原圖的e-DCC(邊雙聯通分量),將其縮成一個點.此時,原圖成了一棵樹,給定一個結論:若縮點後的圖中度為1的節點數量為tot,則需要新增
條邊( 即為
)
求出原圖的e-DCC:求出所有的橋後,將其標記,第二次遍歷時不訪問橋,則每一次便利的點集均為一個e-DCC.注意存在重邊的處理.
縮點:方法比較多,亂搞就好
程式碼
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stack>
#define IL inline
using namespace std;
IL int read()
{
char c = getchar();
int sum = 0 ,k = 1;
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
return sum * k;
}
int n, m;
int to[20005], nxt[20005];
int last[5005];
int cnt = -1;
IL void add(int u, int v)
{
to[++cnt] = v; nxt[cnt] = last[u]; last[u] = cnt;
to[++cnt] = u; nxt[cnt] = last[v]; last[v] = cnt;
}
int dfn[5005], low[5005];
bool is_bridge[20005];
int col, belong[5005];
int degree[5005];
stack<int> bridge;
IL int min_(int x, int y) { return x < y ? x : y; }
IL void tarjan(int u, int pre)
{
dfn[u] = low[u] = ++cnt;
for(int i = last[u], v; i != -1; i = nxt[i])
if((i ^ pre) != 1)
{
v = to[i];
if(!dfn[v])
{
tarjan(v, i);
low[u] = min_(low[u], low[v]);
if(low[v] > dfn[u])
{
is_bridge[i] = is_bridge[i ^ 1] = 1;
bridge.push(i);
}
}else
low[u] = min_(low[u], dfn[v]);
}
}
IL void dfs(int u, int k)
{
belong[u] = k;
for(int i = last[u]; i != -1; i = nxt[i])
if(!is_bridge[i] && !belong[to[i]])
dfs(to[i], k);
}
int main()
{
n = read(); m = read();
memset(last, -1, sizeof(last));
for(int i = 1, x; i <= m; ++i)
{
x = read();
add(x, read());
}
cnt = 0; tarjan(1, -1);
for(int i = 1; i <= n; ++i)
if(!belong[i])
dfs(i, ++col);
for(int t = bridge.size(), x; t; --t)
{
x = bridge.top(); bridge.pop();
++degree[belong[to[x]]]; ++degree[belong[to[x ^ 1]]];
}
int tot = 0;
for(int i = 1; i <= col; ++i)
if(degree[i] == 1)
++tot;
printf("%d\n", (tot + 1) >> 1);
return 0;
}