题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3394php
题目大意:
给定一个无向图,若是从一个点出发通过一些点和边能回到该点自己,那么一路走过来的这些点和边的集合就是一个环。
一个公园中有 n 个景点,景点之间经过无向的道路来链接,若是至少两个环公用一条路,路上的游客就会发生冲突;若是一条路不属于任何的环,这条路就不必修。
问,有多少路没必要修,有多少路会发生冲突?c++
解题思路:
每个连通块中,若是边数大于点数,这个块中全部的边所有是冲突边。
全部桥为不须要修建的路。spa
实现代码以下:code
#include <bits/stdc++.h> using namespace std; const int maxn = 10010, maxm = 100010; struct Edge { int u, v, nxt; Edge () {}; Edge (int _u, int _v, int _nxt) { u = _u; v = _v; nxt = _nxt; } } edge[maxm<<1]; int n, m, head[maxn], ecnt; void init() { memset(head, -1, sizeof(int)*(n+1)); ecnt = 0; } void addedge(int u, int v) { edge[ecnt] = Edge(u, v, head[u]); head[u] = ecnt ++; edge[ecnt] = Edge(v, u, head[v]); head[v] = ecnt ++; } int dfn[maxn], low[maxn], cnt, bridge_num, crash_num; stack<int> stk; set<int> bcc; void tarjan(int u, int pre) { dfn[u] = low[u] = ++cnt; for (int i = head[u]; i != -1; i = edge[i].nxt) { int v = edge[i].v; if (v == pre) continue; if (!dfn[v]) { stk.push(i); tarjan(v, u); low[u] = min(low[u], low[v]); if (low[v] >= dfn[u]) { int id; int tmp_cnt = 0; bcc.clear(); do { tmp_cnt ++; id = stk.top(); stk.pop(); bcc.insert(edge[id].u); bcc.insert(edge[id].v); } while (edge[id].u != u || edge[id].v != v); if (tmp_cnt > bcc.size()) crash_num += tmp_cnt; } if (low[v] > dfn[u]) bridge_num ++; } else if (dfn[v] < dfn[u]) { stk.push(i); low[u] = min(low[u], dfn[v]); } } } int main() { while (~scanf("%d%d", &n, &m) && n) { init(); memset(dfn, 0, sizeof(int)*(n+1)); cnt = bridge_num = crash_num = 0; while (m --) { int a, b; scanf("%d%d", &a, &b); a ++; b ++; addedge(a, b); } for (int i = 1; i <= n; i ++) if (!dfn[i]) tarjan(i, -1); printf("%d %d\n", bridge_num, crash_num); } return 0; }