Bridges Gym - 100712H ? 无向图的边双连通分量,Tarjan缩点
Posted stupid_one
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bridges Gym - 100712H ? 无向图的边双连通分量,Tarjan缩点相关的知识,希望对你有一定的参考价值。
http://codeforces.com/gym/100712/attachments
题意是给定一个无向图,要求添加一条边,使得最后剩下的桥的数量最小。
注意到在环中加边是无意义的。
那么先把环都缩成一个点,然后重新建立一颗树,找出树的直径就好。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define ios ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> const int maxn = 1e5 + 20; struct Edge { int u, v, tonext; }e[maxn * 2], tree[maxn * 2]; int first[maxn], num; int first_tree[maxn], num_tree; void addEdge(int u, int v) { ++num; e[num].u = u, e[num].v = v, e[num].tonext = first[u]; first[u] = num; } int DFN[maxn], low[maxn], when, st[maxn], top; int id[maxn], toSelid; bool vis[maxn]; void tarjan(int cur, int fa) { DFN[cur] = low[cur] = ++when; //时间戳 st[++top] = cur; //进栈 vis[cur] = true; for (int i = first[cur]; i; i = e[i].tonext) { int v = e[i].v; // if (v == fa) continue; if (!DFN[v]) { //没访问过 tarjan(v, cur); low[cur] = min(low[cur], low[v]); } else if (vis[v]) { // 访问过,而且还在栈里 low[cur] = min(low[cur], DFN[v]); } } if (low[cur] == DFN[cur]) { //这个是强连通分量的根节点。 ++toSelid; do { id[st[top]] = toSelid; //块id // sum[toSelId]++; //id节点个数 // printf("%d ", st[top]); vis[st[top]] = false; top--; } while (cur != st[top + 1]); // printf("\n"); } } void solveTarjan(int n) { memset(DFN, 0, sizeof DFN); memset(low, 0, sizeof low); memset(vis, 0, sizeof vis); when = top = toSelid = 0; for (int i = 1; i <= n; ++i) { if (!DFN[i]) tarjan(i, i); } } void addEdgeTree(int u, int v) { ++num_tree; tree[num_tree].u = u, tree[num_tree].v = v, tree[num_tree].tonext = first_tree[u]; first_tree[u] = num_tree; } struct bfsnode { int cur, cnt; bfsnode(int _cur, int _cnt) { cur = _cur; cnt = _cnt; } }; int tree_diameter(int begin, bool flag) { memset(vis, 0, sizeof vis); queue<struct bfsnode> que; while (!que.empty()) que.pop(); que.push(bfsnode(begin, 0)); vis[begin] = true; int to = begin, mx = 0; while (!que.empty()) { struct bfsnode t = que.front(); que.pop(); for (int i = first_tree[t.cur]; i; i = tree[i].tonext) { int v = tree[i].v; if (vis[v]) continue; vis[v] = true; que.push(bfsnode(v, t.cnt + 1)); if (mx < t.cnt + 1) { to = v; mx = t.cnt + 1; } } } if (flag) return mx; else return to; } void work() { memset(first, 0, sizeof first); memset(first_tree, 0, sizeof first_tree); num = num_tree = 0; int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= m; ++i) { int u, v; scanf("%d%d", &u, &v); addEdge(u, v); addEdge(v, u); } solveTarjan(n); // for (int i = 1; i <= n; ++i) { // cout << id[i] << " "; // } for (int i = 1; i <= n; ++i) { for (int j = first[i]; j; j = e[j].tonext) { int v = e[j].v; if (id[i] == id[v]) continue; addEdgeTree(id[i], id[v]); addEdgeTree(id[v], id[i]); } } int res = tree_diameter(1, 0); int di = tree_diameter(res, 1); int ans = toSelid - di - 1; ans = max(ans, 0); cout << ans << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif int t; scanf("%d", &t); while (t--) work(); return 0; }
以上是关于Bridges Gym - 100712H ? 无向图的边双连通分量,Tarjan缩点的主要内容,如果未能解决你的问题,请参考以下文章
POJ2288 Islands and Bridges (DP)