/* *State: ZOJ2588 530 MS 12788 KB GNU C++ *题目大意: * 给出一个无向图,输入n(表示n个定点,1~n), m(m条边,有重边), * (2 <= N <= 10 000, 1 <= M <= 100 000),求这个无向图中的桥, * 并输出桥属于输入中边的id. *解题思路: * 知道求割点与求割边是很相似的,自己用笔模拟一下就知道,如果 * 存在low[v] > dfn[u].那么uv就是割边。看似与割点异常类似,但是 * 用了原始的求割点的tarjan敲了几遍后发现,不行。因为求割点的时 * 候由于条件是low[v] >= dfn[u],所以它可能回溯回自己的父亲节点, * 然后就更新了自己的low[v].之后求割边的条件就实现不出来了。 * * 发现了这个问题之后,就修改了tarjan算法,把参数由一个当前节点 * 改为2个,一个父亲结点,一个它自己,然后搜。将一个节点的所有孩 * 子节点都搜一遍,之后再判断,只要dfn[n] == low[n],就说明n跟它 * 的父亲节点构成的边是割边。为什么?因为dfn[n] == low[n],就说明 * 当前节点n的所有孩子节点都最多只能到达当前节点n的孩子节点。也就 * 是说n跟它的father是关节边。 * * ps:为什么求割点是把判断放在循环内,求割边要放在循环外(其实放 * 循环外面也可以,但是要注意回溯判断的不同,要修改根节点的情况)。 * 用笔模拟下即可。该题有重边,我先把它当无重边算,之后在判断割边 * 的时候判断下是否为重边即可。 */
View Code
#include <iostream> #include <vector> #include <cstdio> #include <algorithm> #include <utility> #include <cstring> using namespace std; typedef struct _node { int v, id, num; _node():num(0) {}; }N; const int MAX = 10005; vector<N> vec[MAX]; int dfn[MAX], low[MAX], step, id; int ans[MAX * 10], cnt; void addEdge(int u, int v) { bool flag = false; for(unsigned i = 0; i < vec[u].size(); i++) { if(vec[u][i].v == v) { flag = true; vec[u][i].num++; for(unsigned j = 0; j < vec[v].size(); j++) { if(vec[v][j].v == u) { vec[v][j].num++; break; } } id++; break; } } if(flag == false) { N tmp; tmp.v = v, tmp.id = id++; tmp.num = 1; vec[u].push_back(tmp); tmp.v = u; vec[v].push_back(tmp); } } void tarjan(int father, int n) { dfn[n] = low[n] = ++step; for(unsigned i = 0; i < vec[n].size(); i++) { int son = vec[n][i].v; if(dfn[son] == -1) { tarjan(n, son); low[n] = min(low[n], low[son]); } else if(son != father) low[n] = min(low[n], dfn[son]); } if(dfn[n] == low[n]) { int son = n; n = father; for(unsigned k = 0; k < vec[n].size(); k++) { if(son == vec[n][k].v) { if(vec[n][k].num == 1) { ans[cnt++] = vec[n][k].id; } break; } } } } void init() { id = 1; step = cnt = 0; for(int i = 0; i < MAX; i++) { vec[i].clear(); dfn[i] = low[i] = -1; } } int main(void) { #ifndef ONLINE_JUDGE //freopen("in.txt", "r", stdin); #endif int cas; scanf("%d", &cas); while(cas--) { init(); int n, m; scanf("%d %d", &n, &m); for(int i = 0; i < m; i++) { int u, v; scanf("%d %d", &u, &v); addEdge(u, v); } dfn[1] = low[1] = ++step; tarjan(1, 1); printf("%d\n", cnt); if(cnt) { sort(ans, ans + cnt); printf("%d", ans[0]); for(int i = 1; i < cnt; i++) { printf(" %d", ans[i]); } printf("\n"); } if(cas) printf("\n"); } return 0; }