题目链接:http://poj.org/problem?id=3177。
思路:这道题目给出一个无向连通图,要求至少添加多少条边才能够使得任意一对顶点间至少有两条不同的路径(没有相同的边,但可以有共同的中间顶点),利用tarjan求出该连通图的边双连通分量,压缩成一个点,最后能构成一棵树,那么添加的边数=(树中度为1的节点数+1)/2,代码如下:
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN = 5002;
int n, m, s, e;
vector<int> graph[MAXN];
int pre[MAXN], lowlink[MAXN], degree[MAXN];
int dfs_clock;
int g[MAXN][MAXN];
void Tarjan(int u, int source_edge) {
pre[u] = lowlink[u] = ++dfs_clock;
for (int i = 0; i < graph[u].size(); i++) {
int v = graph[u][i];
if (v == source_edge) continue;//reverse edge
if (!pre[v]) {//not visited yet
Tarjan(v, u);
lowlink[u] = min(lowlink[u], lowlink[v]);
} else {
lowlink[u] = min(lowlink[u], pre[v]);
}
}
}
int main() {
cin >> n >> m;
//init
dfs_clock = 0;
memset(pre, 0, sizeof(pre));
memset(lowlink, 0, sizeof(lowlink));
memset(degree, 0, sizeof(degree));
for (int i = 0; i < m; i++) {
cin >> s >> e;
g[s][e] = g[e][s] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = i+1; j <= n; j++) {
if (g[i][j]) {
graph[i].push_back(j);
graph[j].push_back(i);
}
}
}
Tarjan(1, -1);
for (int i = 1; i <= n; i++) {
for (int j = 0; j < graph[i].size(); j++) {
int v = graph[i][j];
if (lowlink[i] != lowlink[v]) {
degree[lowlink[v]]++;
}
}
}
int ans = 0;
for (int i = 1; i <= MAXN; i++) {
if (degree[i] == 1) ans++;
}
cout << (ans+1)/2 << endl;
return 0;
}