题意:有n个点,m条无向边,问加一条边,最少可以剩下几个桥
思路:双联通分量缩点,然后在树上求最长路,就是要加的边。
另外:不能用桥的数量去当做双联通分量的个数,wa了无数回才发现。
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
int n, m, h[N], cnt, ans;
int dfn[N], low[N], inde, bridge[N][2], ins[N], scc[N], bnum;
int dis[N], vis[N];
stack<int> s;
struct node {
int v, net;
} no[N * 7];
void add(int u, int v) {
no[cnt].v = v;
no[cnt].net = h[u];
h[u] = cnt++;
}
void tarjan(int u, int edge) {
dfn[u] = low[u] = ++inde;
ins[u] = 1;
s.push(u);
int fl = 0;
for(int i = h[u]; ~i; i = no[i].net) {
int v = no[i].v;
if(v == edge && !fl) {//有重边
fl = 1;
continue;
}
if(!dfn[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(dfn[u] < low[v]) {
bridge[bnum][0] = u;
bridge[bnum++][1] = v;
}
} else if(ins[v])
low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]) {
int t;
ans++;
do {
t = s.top();
scc[t] = ans;
s.pop();
ins[t] = 0;
} while(t != u);
}
}
void dfs(int u) {
vis[u] = 1;
for(int i = h[u]; ~i; i = no[i].net) {
int v = no[i].v;
if(!vis[v]) {
dis[v] = dis[u] + 1;
dfs(v);
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
while(cin >> n >> m && (n + m)) {
memset(h, -1, sizeof h);
memset(dfn, 0, sizeof dfn);
memset(ins, 0, sizeof ins);
memset(scc, 0, sizeof scc);
memset(bridge, 0, sizeof bridge);
bnum = ans = inde = cnt = 0;
for(int x, y, i = 0; i < m; i++) {
cin >> x >> y;
add(x, y), add(y, x);
}
tarjan(1, 0);
cnt = 0;
memset(h, -1, sizeof h);
int maxx = 0, s;
for(int i = 0; i < bnum; i++) {
int x = scc[bridge[i][0]], y = scc[bridge[i][1]];
add(x, y), add(y, x);
}
memset(dis, 0x3f, sizeof dis);
memset(vis, 0, sizeof vis);
dis[1] = 0;
dfs(1);
for(int i = 1; i <= ans; i++) {
if(dis[i] > maxx && dis[i] != 0x3f3f3f3f) {
maxx = dis[i];
s = i;
}
}
memset(dis, 0x3f, sizeof dis);
memset(vis, 0, sizeof vis);
dis[s] = 0;
dfs(s);
for(int i = 1; i <= ans; i++)
if(dis[i] > maxx && dis[i] != 0x3f3f3f3f)
maxx = dis[i];
cout << ans - 1 - maxx << endl;
}
return 0;
}