tarjan+LCA。
先用tarjan进行缩点。
然后用dfn[u] < low[v]判断是不是桥。
讲桥标记起来并且计算出桥数。
对于每个案例的u和v
利用LCA用fath数组先找到u和v的祖先,如果在路径中出现的桥,就把桥标记成普通边并将桥数–。
然后输出对应的桥数
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn = 100006;
const int maxm = 200005;
int n, m, tol, cnt;
int brinum;
struct Node {
int u;
int v;
int next;
};
Node node[2 * maxm];
int dfn[maxn];
int low[maxn];
int fath[maxn];
int head[maxn];
bool vis[maxn];
bool bridge[maxn];
void init() {
brinum = tol = cnt = 0;
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(node, 0, sizeof(node));
memset(fath, 0, sizeof(fath));
memset(head, -1, sizeof(head));
memset(vis, false, sizeof(vis));
memset(bridge, 0, sizeof(bridge));
}
void addnode(int u, int v) {
node[tol].u = u;
node[tol].v = v;
node[tol].next = head[u];
head[u] = tol++;
}
void dfs(int u, int fa) {
dfn[u] = low[u] = ++cnt;
fath[u] = fa;
for(int i=head[u]; i != -1; i=node[i].next) {
int v = node[i].v;
if(!dfn[v]) {
dfs(v, u);
low[u] = min(low[u], low[v]);
} else if(v != fa) {
low[u] = min(low[u], dfn[v]);
}
}
}
void tarjan() {
dfs(1, 1);
}
void findbridge() {
for(int v=1; v<=n; v++) {
int u = fath[v];
if(dfn[u] < low[v] && u != v) {
bridge[v] = true;
brinum++;
}
}
}
void LCA(int u, int v) {
while(dfn[u] > dfn[v]) {
if(bridge[u]) {
brinum--;
bridge[u] = false;
}
u = fath[u];
}
while(dfn[v] > dfn[u]) {
if(bridge[v]) {
brinum--;
bridge[v] = false;
}
v = fath[v];
}
while(u != v) {
if(bridge[u]) {
bridge[u] = false;
brinum--;
}
if(bridge[v]) {
bridge[v] = false;
brinum--;
}
u = fath[u];
v = fath[v];
}
printf("%d\n", brinum);
}
int main() {
int cas = 1;
while(scanf("%d%d",&n, &m), n||m) {
init();
for(int i=1; i<=m; i++) {
int u, v;
scanf("%d%d", &u, &v);
addnode(u, v);
addnode(v, u);
}
tarjan();
findbridge();
int q;
scanf("%d", &q);
printf("Case %d:\n", cas++);
for(int i=1; i<=q; i++) {
int u, v;
scanf("%d%d", &u, &v);
LCA(u, v);
}
puts("");
}
return 0;
}