关于桥与双连通分支的定义及求法void大神给出了很详尽的介绍图的割点、桥与双连通分支
总结几条做题过程中发现的关于边双连通分量的性质:
1.将图中每个边连通分量缩为一个点后,只连端点不位于同一连通分量中的边,则将图转换成了一棵树,且树中的边都是父子边。
2.在对图进行搜索时,图中的边分为父子边和返祖边(交叉边),则一个具有n个点的边连通分量中有且仅有n-1条父子边,且可由着n-1以条边连成一棵树,剩余的边都是返祖边。
关于双连通图的构造和判定等基本问题void文章里有详细介绍,我的《连通性问题》中也有写。
poj3694 Network
题意:讯问在现有网络中添加一条边<a,b>后图中有多少条桥。
显然,若ab位于同一连通分支时不会影响桥,因此变为缩点后的树中两点之间路径上有多少条桥,由于在求双连通时记录了每个点的深度,因此不必单独求lca只需延父节点向上走,知道两个点的某个祖先相同,在寻找lca的过程中可以顺便提及出有多少条桥。
int LCA(int a, int b) {
if(dfn[a]<dfn[b]){
int temp=a;
a=b;
b=temp;
}
while(dfn[a]>dfn[b]){
if(bridge[a]){
sum--;
bridge[a]=false;
}
a=fa[a];
}
while(a!=b){
if(bridge[a]){sum--;bridge[a]=false;}
if(bridge[b]){sum--;bridge[b]=false;}
a=fa[a];b=fa[b];
}
return sum;
}
poj1515 Street Direction / poj1438 One-Way Traffic
题意:有m条无向边确保n个点两两可达,要求将尽可能多的双向边变为单向边,使得任意两点之间仍然可达,并给出一组方案。
解法:对于无向图的桥,肯定要保持双向,对于双连通分量分量内的点,只要确保构成果敢个环就可以,一开始想到了dfs求环路,后来想到了染色,其实构成环路的边就是搜索时的父子边和返祖边,按照原本的方向构造就可以。
1438是1515的延伸,有些路已经是单向的了。其实很简单,只要在加边的时候加单向边,就相当于给一条无向边规定了性质,然后做相同的处理即可
public class Main{
int maxn=1010,maxm=10010;
class BCC {
class node {
int ne, be;
int type;
node(int be, int ne) {
this.ne = ne;
this.be = be;
}
}
node buf[] = new node[maxm];
int E[] = new int[maxn], len, n;
int dfn[] = new int[maxn], low[] = new int[maxn], cnt;
int vis[] = new int[maxn], fa[] = new int[maxn], sum;
boolean bridge[] = new boolean[maxm];
void init(int n) {
this.n = n;
Arrays.fill(E, -1);
len = 0;
}
void add(int a, int b) {
buf[len] = new node(b, E[a]);
E[a] = len++;
buf[len] = new node(a, E[b]);
E[b] = len++;
}
void dfs(int a) {
vis[a] = 1;
dfn[a] = low[a] = ++cnt;
for (int i = E[a]; i != -1; i = buf[i].ne) {
int b = buf[i].be;
if (vis[b] == 1 && b != fa[a]){
buf[i].type=1;//返祖边
low[a] = Math.min(low[a], dfn[b]);
}
if (vis[b] == 0) {
buf[i].type=2;//父子边
fa[b] = a;
dfs(b);
low[a] = Math.min(low[b], low[a]);
if (low[b] > dfn[a]) {
buf[i].type=3;//
// System.out.println(a+" bb "+b+" "+i);
}
}
}
vis[a] = 2;
}
void solve() {
Arrays.fill(dfn, 0);
Arrays.fill(low, 0);
Arrays.fill(bridge, false);
Arrays.fill(vis, 0);
cnt = sum = 0;
for (int i = 1; i <= n; i++)
fa[i] = i;
dfs(1);
}
void go(){
for(int i=1;i<=n;i++)
for(int j=E[i];j!=-1;j=buf[j].ne){
//System.out.println(i+" "+j);
if(buf[j].type==0)
continue;
int b=buf[j].be;
System.out.println(i+" "+b);
if(buf[j].type==3)
System.out.println(b+" "+i);
}
}
}
StreamTokenizer in = new StreamTokenizer(new BufferedReader(
new InputStreamReader(System.in)));
int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
BCC bcc=new BCC();
void run() throws IOException
{
int cas=0;
while(++cas>0){
int n=nextInt();
int m=nextInt();
if(n==0)
break;
System.out.println(cas+"\n");
bcc.init(n);
for(int i=1;i<=m;i++)
bcc.add(nextInt(), nextInt());
bcc.solve();
bcc.go();
System.out.println("#");
}
}
public static void main(String[] args) throws IOException {
new Main().run();
}
}