大意略。
无向图求双连通块,冲突的边,即缩块之后如果点数>边数,说明无环,则该路径可以去掉。如果有环,则环中所有的边都冲突。
#include <iostream> #include <cstdlib> #include <cstdio> #include <string> #include <cstring> #include <cmath> #include <vector> #include <queue> #include <algorithm> #include <map> using namespace std; const int maxn = 10010; const int maxm = 100010*2; struct Edge { int v, w; int next; int id; }edge[maxm]; int first[maxn], stack[maxn], ins[maxn], dfn[maxn], low[maxn]; int belong[maxn]; int deg[maxn]; int block[maxn]; int n, m; int cnt; int scnt, top, tot; void init() { cnt = 0; scnt = top = tot = 0; memset(first, -1, sizeof(first)); memset(dfn, 0, sizeof(dfn)); memset(ins, 0, sizeof(ins)); memset(block, 0, sizeof(block)); } void read_graph(int u, int v) { edge[cnt].v = v; edge[cnt].next = first[u], first[u] = cnt++; } bool vis[maxn]; int ans1, ans2; void count_edge() { memset(vis, 0, sizeof(vis)); int sum = 0; for(int i = 1; i <= block[0]; i++) vis[block[i]] = 1; for(int i = 1; i <= block[0]; i++) { int u = block[i]; for(int e = first[u]; e != -1; e = edge[e].next) { int v = edge[e].v; if(vis[v]) sum++; } } sum /= 2; if(sum < block[0]) ans1 += sum; if(sum > block[0]) ans2 += sum; } void dfs(int u) { int v; low[u] = dfn[u] = ++tot; stack[top++] = u; ins[u] = 1; for(int e = first[u]; e != -1; e = edge[e].next) { v = edge[e].v; if(!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); if(dfn[u] <= low[v]) { block[0] = 0; int t; do { t = stack[--top]; block[++block[0]] = t; ins[t] = 0; }while(v != t); block[++block[0]] = u; count_edge(); } } else if(ins[v]) low[u] = min(low[u], dfn[v]); } } void Tarjan() { for(int i = 0; i < n; i++) if(!dfn[i]) dfs(i); } int read_case() { init(); scanf("%d%d", &n, &m); if(!n) return 0; while(m--) { int u, v, w; scanf("%d%d", &u, &v); read_graph(u, v); read_graph(v, u); } return 1; } void solve() { ans1 = ans2 = 0; Tarjan(); printf("%d %d\n", ans1, ans2); } int main() { while(read_case()) { solve(); } return 0; }