标签:
题意:有n个点,m条边,有重边。现在可以任意在图上添加一条边,求桥的最少数目。
题解:思路就是求出双连通分量之后缩点成为一棵树,然后求出树的直径,连接树的直径就能减少最多的桥。
难点在于:有!重!边!
像我这样习惯于无脑用模板的人来说。。。。头疼死了。。。。。。
既然有重边,dfs的时候就不要标记点,以边为标记,然后照常求分量就好了。
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <vector> #include <bitset> #include <cstdio> #include <queue> #include <stack> #include <cmath> #include <list> #include <map> #include <set> #define pk(x) printf("x=%d\n", x) using namespace std; #define PI acos(-1.0) #define EPS 1E-6 #define clr(x,c) memset(x,c,sizeof(x)) typedef long long ll; typedef pair<int, int> PII; const int N = 200005; const int M = 2000005; struct Edge { int from, to, next; int cut; } edge[M]; int cnt_edge; int head[N]; void add_edge(int u, int v) { edge[cnt_edge].from = u; edge[cnt_edge].to = v; edge[cnt_edge].next = head[u]; edge[cnt_edge].cut = 0; head[u] = cnt_edge++; } int dfn[N]; int idx; int low[N]; int stk[N]; int top; int kind[N]; int cnt; bool in[N]; void tarjan(int u, int pre) { low[u] = dfn[u] = ++idx; in[u] = true; stk[++top] = u; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (i == pre) continue; if (!dfn[v]) { tarjan(v, i^1); low[u] = min(low[u], low[v]); if (low[v] > dfn[u]) { edge[i].cut = true; edge[i ^ 1].cut = true; } } else low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) { cnt++; int v; do { v = stk[top--]; in[v] = false; kind[v] = cnt; } while (u != v); } } vector<int> G[N]; int ans, ansv; void dfs(int u, int fa, int d) { if (ans < d) { ans = d; ansv = u; } for (unsigned i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if (v == fa) continue; dfs(v, u, d+1); } } void init() { for (int i = 0; i < N; ++i) G[i].clear(); memset(dfn, 0, sizeof dfn); memset(head, -1, sizeof head); top = idx = cnt = cnt_edge = 0; } int main() { int n, m; while (~scanf("%d%d", &n, &m)) { if (n + m == 0) break; init(); int u, v; for (int i = 0; i < m; ++i) { scanf("%d%d", &u, &v); add_edge(u, v); add_edge(v, u); } tarjan(1, -1); int ret = 0; for (int i = 0; i < cnt_edge; ++i) { if (edge[i].cut) { int u = edge[i].from; int v = edge[i].to; if (u < v) ret++; G[ kind[u] ].push_back( kind[v] ); } } ans = 0; ansv = 0; dfs(1, -1, 0); ans = 0; dfs(ansv, -1, 0); printf("%d\n", ret-ans); } return 0; } /** 6 6 1 2 2 3 3 4 4 5 2 6 6 2 6 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 1 2 0 0 */
======
wa:12次,tle:1次,mle:3次,ce:2次
一颗赛艇。。。
标签:
原文地址:http://www.cnblogs.com/wenruo/p/5882958.html