类型:无向图割边
题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1588
来源:Andrew Stankevich's Contest #5
思路:题目要求的是无向图的所有的割边,可以通过Tarjan算法求解,无向图中的一条边(u, v)是桥,当且仅当(u, v)为生成树中的边,且满足dfn[u] < low[v] 根据该性质判断并记录图中的桥。有重边,用邻接表存图。
!!!邻接表需要判断是否是同一条边
// zoj 1588 Burning Bridges
// 360ms 2696kb
#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace std;
#define MAXN 10010
#define MAXM 200020
typedef long long LL;
bool sign;
bool vis[MAXN];
int cnt, maxn, k, len, t, n, m;
int head[MAXN];
int endd[MAXN], low[MAXN], step[MAXN];
struct node {
int nxt, v, i;
}p[MAXM];
void addedge(int u, int v, int i) {
p[k].v = v;
p[k].i = i;
p[k].nxt = head[u];
head[u] = k++;
p[k].v = u;
p[k].i = i;
p[k].nxt = head[v];
head[v] = k++;
}
void init() {
memset(vis, false, sizeof(vis));
memset(step, -1, sizeof(step));
memset(head, -1, sizeof(head));
memset(endd, 0, sizeof(endd));
low[1] = step[1] = cnt = 1;
k = 2;
len = 0;
vis[1] = true;
}
void dfs(int u, int edge) {
int v, i;
for(i = head[u]; i != -1; i = p[i].nxt) {
if((i ^ 1) == edge)
continue;
v = p[i].v;
if(!vis[v]) {
vis[v] = true;
low[v] = step[v] = (++cnt);
dfs(v, i);
low[u] = min(low[u], low[v]);
if(low[v] > step[u])
endd[len++] = p[i].i;
}
else
low[u] = min(low[u], step[v]);
}
}
int main() {
int i, u, v;
scanf("%d", &t);
while(t--) {
init();
scanf("%d %d", &n, &m);
for(i = 1; i <= m; ++i) {
scanf("%d %d", &u, &v);
addedge(u, v, i);
}
dfs(1, -1);
printf("%d\n", len);
sort(endd, endd + len);
for(i = 0; i < len; ++i)
(i == 0) ? printf("%d", endd[i]) : printf(" %d", endd[i]);
if(len > 0)
printf("\n");
if(t > 0)
printf("\n");
}
return 0;
}