题意
N个点M条边的图,问如果加一条边, 最少可以剩下多少个桥?
思路
边双联通缩点以后形成一棵的树,所有树边均为桥。
环上的边显然不是桥,所以我们使得最长的一条链称为环,也就是直径。
那么答案就是:原来的桥数 - 直径
坑点是:有重边!!!重边自然不算是桥了。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXM = 2e6 + 5;
//边双连通分量
struct Edge
{
int from, to;
Edge(int u, int v) : from(u), to(v) {}
};
struct EdgeBCC//边双连通分量
{
int n, m;
int DFN[MAXN], LOW[MAXN], bccno[MAXN], dfs_clock, bcc_cnt;
bool isbridge[MAXM];
vector<Edge> edges;
vector<int> G[MAXN];
stack<int> S;
void init(int n)
{
this->n = n, m = 0;
edges.clear();
for (int i = 0; i <= n; i++) G[i].clear();
}
void AddEdge (int from, int to)
{
edges.emplace_back(from, to);
edges.emplace_back(to, from);
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
void dfs(int u, int fa)
{
DFN[u] = LOW[u] = ++dfs_clock;
S.push(u);
for (auto id : G[u])
{
if ((id^1) == fa) continue;
int v = edges[id].to;
if (!DFN[v])
{
dfs(v, id);
LOW[u] = min(LOW[u], LOW[v]);
if (LOW[v] > DFN[u])//桥
isbridge[id] = isbridge[id^1] = true;
}
else if (!bccno[v] && LOW[u] > DFN[v])
LOW[u] = min(LOW[u], DFN[v]);
}
if (LOW[u] == DFN[u])
{
bcc_cnt++;
while (1)
{
int x = S.top(); S.pop();
bccno[x] = bcc_cnt;
if (x == u) break;
}
}
}
void find_bcc()
{ // 注意点的编号从0开始, 连通分量的编号从1开始
dfs_clock = bcc_cnt = 0;
memset(DFN, 0, sizeof(DFN)), memset(bccno, 0, sizeof(bccno));
memset(isbridge, 0, sizeof(isbridge));
for (int i = 0; i < n; i++)
if (!DFN[i]) dfs(i, -1);
}
}gao;
int d[MAXN], s;
vector<int> G[MAXN];
void dfs(int u, int fa)
{
for (auto v: G[u])
{
if (v == fa) continue;
d[v] = d[u] + 1;
if (d[v] > d[s]) s = v;
dfs(v, u);
}
}
int main()
{
int n, m;
while (~scanf("%d%d", &n, &m) && (n + m))
{
gao.init(n);
while (m--)
{
int u, v; scanf("%d%d", &u, &v);
u--, v--;
gao.AddEdge(u, v);
}
gao.find_bcc();
for (int i = 0; i <= gao.bcc_cnt; i++) G[i].clear();
for (int i = 0; i < gao.edges.size(); i += 2)
{
if (!gao.isbridge[i]) continue;
Edge& e = gao.edges[i];
int u = gao.bccno[e.from], v = gao.bccno[e.to];
G[u].push_back(v);
G[v].push_back(u);
}
s = 1;
d[s] = 0; dfs(s, 0);
d[s] = 0; dfs(s, 0);
int ans = (gao.bcc_cnt - 1) - d[s];
printf("%d\n", ans);
}
return 0;
}
/*
4 4
1 2 1 3 1 4 2 3
6 6
1 2 2 3 3 4 4 5 2 6 6 2
7 8
1 2 2 3 3 4 4 5 2 6 6 2 1 3 4 7
5 4
2 1 2 3 2 4 2 5
5 5
2 1 2 3 2 4 2 5 3 4
5 5
1 2 2 3 3 4 3 4 4 5
0 0
*/