关于桥与双连通分支的定义及求法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(); } }