这篇是介绍利用tarjan算法求桥,其实和上一篇求割点的方法很相似,大致思路是一样的,不过因为专门涉及到一道题,所以在这里分为两篇来写,而且虽然相似,但是还是有所不同,在这里会对比二者不同来介绍求桥的方法。
割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图。
求割点的是dfn[u]<=low[v],这样确保了v不经过u就无法到达u的父亲节点。
求割边的不等式是dfn[u]<low[v],少了等于号,其实思索一下很容易发现,之所以会有dfn[u]==low[v],是因为有多条边可以使v到达u,而割边的话,必须是v到达u只有一条边,就是直接连接他们的那条边,但是对于无向图中的每条边都被分解成了两条有向边来存储,这样势必会使low[v]==dfn[u](通过树枝边来更新low时是不会出现问题的,但是通过后向边来更新的时候是会访问到父亲节点的),所以我们要加入一个新数组pre[i]来存储i节点的父亲节点,这样如果出现后向边直接指向其父亲节点的情况,就不对low进行更新,这样也有效的消除了重边带来的影响。
而且还有一点,对比下面的代码,我们可以发现对割点的判断是每一次深搜回溯后更新了low之后就判断,但是对割边的判断则是在搜索完当前节点的所有搜索树之后才判断的,这也很容易理解,因为我们在查找割点的时候,<k,e>是一条出边,也就是说我们是直接判断k是否是割点,而在查找割边的时候因为一个点可能有很多个子节点,但是在深搜过程中只会有一个父亲节点,所以我们用pre存储它的父亲节点,这样必须查找完它的全部子树,确定没有其他的边到父节点之后才能确定割边。
下面贴题和代码,UVA 796
In a computer network a link L, which interconnects two servers, is considered critical if there are at least two servers A and B such that all network interconnection paths between A and B pass through L. Removing a critical link generates two disjoint sub–networks such that any two servers of a sub–network are interconnected. For example, the network shown in figure 1 has three critical links that are marked bold: 0 -1, 3 - 4 and 6 - 7. Figure 1: Critical links It is known that:
1. the connection links are bi–directional;
2. a server is not directly connected to itself;
3. two servers are interconnected if they are directly connected or if they are interconnected with the same server;
4. the network can have stand–alone sub–networks. Write a program that finds all critical links of a given computer network.
Input
The program reads sets of data from a text file. Each data set specifies the structure of a network and has the format: no of servers server0 (no of direct connections) connected server . . . connected server . . . serverno of servers (no of direct connections) connected server . . . connected server The first line contains a positive integer no of servers(possibly 0) which is the number of network servers. The next no of servers lines, one for each server in the network, are randomly ordered and show the way servers are connected. The line corresponding to serverk, 0 ≤ k ≤ no of servers − 1, specifies the number of direct connections of serverk and the servers which are directly connected to serverk. Servers are represented by integers from 0 to no of servers − 1.Input data are correct. The first data set from sample input below corresponds to the network in figure 1, while the second data set specifies an empty network.
Output
The result of the program is on standard output. For each data set the program prints the number of critical links and the critical links, one link per line, starting from the beginning of the line, as shown in the sample output below. The links are listed in ascending order according to their first element. The output for the data set is followed by an empty line.
Sample Input
8
0 (1) 1
1 (3) 2 0 3
2 (2) 1 3
3 (3) 1 2 4
4 (1) 3
7 (1) 6
6 (1) 7
5 (0)
0
Sample Output
3 critical links
0 - 1
3 - 4
6 - 7
0 critical links
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 1005
int head[Maxn];
int u[Maxn*Maxn];
int v[Maxn*Maxn];
int _next[Maxn*Maxn];
int pre[Maxn];
int dfn[Maxn];
int low[Maxn];
struct R{
int x,y;
};
R re[Maxn];
int cnt;
int cmp(R a,R b){
if(a.x!=b.x) return a.x<b.x;
else return a.y<b.y;
}
void dfs(int k,int num){
dfn[k]=low[k]=num;
for(int i=head[k];i!=-1;i=_next[i]){
int e=v[i];
if(!dfn[e]) {
pre[e]=k;
dfs(e,++num);
low[k]=min(low[e],low[k]);
}
else if(pre[k]!=e) low[k]=min(low[k],dfn[e]);
}
if(pre[k]!=-1&&dfn[pre[k]]<low[k]){
re[cnt].x=min(k,pre[k]);
re[cnt].y=max(pre[k],k);
cnt++;
}
}
int main(){
int n;
while(~scanf("%d",&n)){
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
int c=0;
cnt=0;
memset(pre,-1,sizeof(pre));
for(int i=0;i<n;i++){
int s,t,k;
scanf("%d",&s);
while(getchar()!='(') ;
scanf("%d",&k);
getchar();
for(int j=0;j<k;j++){
scanf("%d",&t);
u[c]=s;
v[c]=t;
_next[c]=head[s];
head[s]=c++;
}
}
for(int i=0;i<n;i++) if(!dfn[i]) dfs(i,1);
sort(re,re+cnt,cmp);
printf("%d critical links\n",cnt);
for(int i=0;i<cnt;i++){
printf("%d - %d\n",re[i].x,re[i].y);
}
printf("\n");
}
}
这里要主要的是每组输出之间要有一行空行
顺便我要吐槽一下,明明建图可以很简单,但是为什么要弄得这么乱,难道是怕别人英文不好但是考看样例猜出来题意???咱们又不是考英语啊