Network

又调试了好久,终于搞定了,又学习了一点点。。呵呵。

题意很简单:给定一个连通的无向图,有Q组操作,每组add一条边(u, v),问图中现有多少条割边。

思路:首先是一个tarjan,求的强连通分支和桥边,然后缩图,这样就得到一棵树,缩图的时候注意一下,将点分层,而且是个有根树,这样对于每增加一条边,就会形成一个环,那么环上的所有边都不是割边了,求的时候,用LCA的方法,分别将bel[u],bel[v]到最近公共祖先结点路径上的边都标志为非割边,这样就可以很快搞定了。

7816618 ylfdrib 3694 Accepted 10908K 391MS C++ 3176B

2010-11-01 09:51:50

代码
//============================================================================
// Name : poj3694.cpp
// Author : birdfly
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include
<iostream>
#include
<stdio.h>
#include
<string.h>
#define NN 100010

using namespace std;

typedef
struct node{
int v;
int vis;
struct node *nxt;
struct node *op;
}NODE;

NODE
*Link[NN];
NODE edg[NN
* 4];

int idx, N, M, scc, time, top;
int bel[NN];
int inSta[NN];
int stk[NN];
int dfn[NN]; //发现时间标号
int low[NN];
int lev[NN]; // 记录每个分支的深度
int mark[NN];
int fa[NN]; // 记录父亲结点
int brig[NN]; // 记录桥边,brig[i] 表示边(fa[i], i)是桥边

void Add(int u, int v){
edg[idx].v
= v;
edg[idx].vis
= 0;
edg[idx].nxt
= Link[u];
edg[idx].op
= edg + idx + 1;
Link[u]
= edg + idx++;
edg[idx].v
= u;
edg[idx].vis
= 0;
edg[idx].nxt
= Link[v];
edg[idx].op
= edg + idx - 1;
Link[v]
= edg + idx++;

}

void Init(){
memset(Link,
0, sizeof(Link));
memset(inSta,
0, sizeof(inSta));
memset(dfn,
0, sizeof(dfn));
idx
= scc = 0;
top
= time = 0;
}

void dfs(int u){// tarjan过程,查找强连通分支和桥
int v;
dfn[u]
= ++time;
low[u]
= dfn[u];
inSta[u]
= 1;
stk[
++top] = u;

for (NODE *p = Link[u]; p; p = p->nxt){
if(!p->vis){
p
->vis = p->op->vis = 1;
if(!dfn[p->v]){
dfs(p
->v);
if(low[u] > low[p->v]){
low[u]
= low[p->v];
}
}
else if (inSta[p->v]){
if(low[u] > dfn[p->v]){
low[u]
= dfn[p->v];
}
}
}
}
if(low[u] == dfn[u]){
scc
++;
do{
v
= stk[top--];
bel[v]
= scc;
inSta[v]
= 0;
}
while(v != u);
}
}

void creattree(int u, int l){ // 深搜的时候,将图按照强连通分支缩成一棵有根树
lev[bel[u]] = l;
for (NODE *p = Link[u]; p; p = p->nxt){
if(mark[p->v]) continue;
mark[p
->v] = 1;
if(!brig[bel[p->v]] && bel[u] != bel[p->v] && low[p->v] == dfn[p->v]){
brig[bel[p
->v]] = 1;
fa[bel[p
->v]] = bel[u];
creattree(p
->v, l + 1);
}
else creattree(p->v, l);/////
}
}

void lca(int x, int y){ // lca求得最近公共祖先,同时更改桥边
if(lev[x] > lev[y]){
x
^= y;
y
^= x;
x
^= y;
}

while(lev[x] < lev[y]){
if(brig[y]){
scc
--;
brig[y]
= 0;
}
y
= fa[y];
}
while(x != y){
if(brig[x]){scc--; brig[x] = 0;}
if(brig[y]){scc--; brig[y] = 0;}
x
= fa[x]; y = fa[y];
}
}
int main() {
int a, b, Q, x, y;
int ca = 1;
while(scanf("%d%d", &N, &M) != EOF){
if(N == 0 && M == 0) break;
printf(
"Case %d:\n", ca++);
Init();
while(M--){
scanf(
"%d%d", &a, &b);
Add(a, b);
}
dfs(
1);
memset(mark,
0, sizeof(int) * (N + 1));
memset(brig,
0, sizeof(int) * (scc + 1));
//int i;
//for (i = 1; i <= N; i++) printf("%d\n", bel[i]);
mark[1] = 1;
creattree(
1, 1);
//for(i = 1; i <= scc; i++) printf("%d\n", fa[i]);
//printf("%d\n", scc);
scanf("%d", &Q);
while(Q--){
scanf(
"%d%d", &a, &b);
if(scc == 1 || bel[a] == bel[b]){
printf(
"%d\n", scc - 1);
}
else{
x
= bel[a];
y
= bel[b];
lca(x, y);
printf(
"%d\n", scc - 1);
}
}
puts(
"");
}
return 0;
}

 

posted on 2010-11-01 11:07  ylfdrib  阅读(1134)  评论(0编辑  收藏  举报