starfish 请问 有向图的bridge怎么求?

along_zju 2001-08-23 11:21:06
还有,能不能推荐几本好的讲图论算法的书,电子版或者是网站也可以,实在是不好找到专讲图论算法的东西,那本清华出的信息学的图论书里面的程序实在是写的太烂了..
...全文
76 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
along_zju 2001-08-24
  • 打赏
  • 举报
回复
我的超星怎么不能连接...我用的是socks5 proxy.
along_zju 2001-08-24
  • 打赏
  • 举报
回复
噢..太谢谢了!
starfish 2001-08-23
  • 打赏
  • 举报
回复
到超星图书馆你可以找到很多图论的书
starfish 2001-08-23
  • 打赏
  • 举报
回复
补充一段程序,delphi下编译通过。

program DFS;

//主程序框架
{$A+,B-,E-,F-,G+,H+,N+,P+,V-,X+} //调试与运行一致
{$D+,I+,L+,O-,Q+,R+,S+,Y+} //调试开关
//{$D-,I-,L-,O+,Q-,R-,S-,Y-} //运行开关

{$apptype console}
uses
math,
SysUtils,
Windows;

Const
MaxSize=8; { 图的最大节点数 }

Type

{ 用邻接矩阵表示图 }
adj_matrix=array [1..MaxSize,1..MaxSize] of integer;


procedure fundament;

const infile='DFS.in';
outfile='DFS.out';
var
probN:integer;
fin,fout:text;
n:integer;
G:adj_matrix;

function init:boolean;
var i,j,k,m:integer;
begin
init:=false;
if eof(fin) then exit;
//insert your codes
readln(fin,n,m);
if n=0 then exit;
inc(probN);
fillchar(G,sizeof(g),0);
for k:=1 to m do
begin
readln(fin,i,j);
G[i,j]:=1;
end;
//end your codes here
init:=true;
end;

{======================================================================
深度优先搜索,找出关于图的结构的信息

存储结构信息的变量说明如下:

/ =0 顶点i到顶点j无边
G-邻接矩阵表示的图,g[i,j]= -| >0 边(i,j)存在且允许访问
\ <0 边(i,j)存在但不允许访问

/ 0 顶点i到j没有边
| 1 (i,j)为树枝边
EdgeType - 边的类型,EdgeType[i,j]=| 2 (i,j)为反向边
| 3 (i,j)为正向边
\ 4 (i,j)为交叉边

d[u] - 第一次访问顶点u时给u盖上的时间戳
f[u] - 当访问完了以u为根的子树上的所有顶点后给u盖上的时间戳

/ 0 白色,未被访问过的节点标白色
c - 顶点颜色表 c[u] = | -1 灰色,已经被访问过一次的节点标灰色
\ 1 黑色,当该节点的所有后代都被访问过标黑色

p - 顶点的前驱表 p[u] - u在深度优先树中的父节点
b - 顶点的度数表 b[u] - 深度优先树中顶点u的度数
l - 顶点的low值表,
l[u]用来纪录顶点u或u的后代所能追溯到的最早(最先被访问)的祖先节点v的d[v]值
/ d[u] u首次被访问
l[u]= | min(l[u],d[v]) 访问反向边(u,v)时
\ min(l[u],l[s]) u的儿子s的关联边全部被访问时


边的分类方法:
1。树枝:
深度优先森林中的边。如果V是在访问边(u,v)时第一次被发现(此时v是白色的),那么
(u,v)是一个树枝。在树枝边中,我们称u为v的父母,既作p[v]=u;
2。反向边:
在深度优先树种连接顶点u到他的祖先的那些非树枝边。环也被认为是反向边。显然,
如果第一次访问(u,v)时v为灰色,则(u,v)为反向边。在对图的深度优先搜索中没有发现
反向边,则该图没有回路。
3。正向边
深度优先树中连接顶点u到他的祖先的那些非树枝边。当第一次访问(u,v)时,v为黑色
且d[u]<d[v],则(u,v)为正向边。
4。交叉边
其它类型的边。他们既可以连接一棵深度优先树中的两个顶点,只要一顶点不是另一
个顶点的祖先,也可以连接分属两棵深度有线数的顶点。当第一次访问(u,v)时,v为黑色
且d[u]>d[v],则(u,v)为交叉边。

*深度优先搜索的复杂度为 θ(V+E)

*有向图或无向图G的深度优先森林中,节点v是节点u的后裔当且仅当 d[u]<d[v]<f[v]<f[u]。

*找出有向图的强连通分支的算法:
S1. 调用DFS(G)以计算出每个节点u的完成时刻f[u];
S2. 计算出G的转置G',其中G'是将G的每一条边反向后得到;
S3. 调用DFS(G'),但在DFS的主循环里按照f[u]递减的顺序考虑各节点;
S4. 输出S3中产生的深度优先森林中每棵树的节点,作为各自独立的强连通分支。

*根据f[v]从大到小对顶点排序,即得到有向图的拓扑排序;

*在对无向图G进行深度优先搜索时,G只有树枝和反向边两种边。

*若无向图的树枝边(u,v)满足l[v]>d[u],即从v及其后代不存在一条连接u的祖先的反向边,
则(u,v)为桥;

* 无向图的节点v是割点当且仅当v具备以下条件成立:
若v是深度优先树的根(p[v]=0),则v的子节点数目超过1;
若v不是深度优先树的根(p[v]>0),则v存在一个子节点w,满足l[w]>=d[v]。

}


{==========================================
!!!!IMPORTANT
对于有向图,请把前面有!!!的行删去;
对于权可以为负的图,请修改前面有!!!的行。

============================================}
procedure DFS(var G:adj_matrix;size:integer);
const
white=0;
gray=-1;
black=1;
var
EdgeType:adj_matrix;
d,f,c,p,b,l:array[1..MaxSize] of integer;
u,time:integer;

procedure DFS_visit(u:integer);
var
v:integer;
begin
c[u]:=gray;
inc(time);
d[u]:=time;
l[u]:=time;
for v:=1 to size do
if G[u,v]>0 then {G[u,v]>0表示边(u,v)存在且未被访问,当边(u,v)不存在时G[u,v]=0}
case c[v] of
white: begin
{!!!} {G[u,v]:=-G[u,v]; {设置(u,v)暂时不可访问的标志,对于有向图,请把此行删去}
EdgeType[u,v]:=1; {(u,v)为树枝边}
inc(b[u]); {深度优先树中顶点u的度数加1}
p[v]:=u; {深度优先树中顶点v的父亲是u}
DFS_visit(v); {深度优先搜索顶点v}
if l[v]<l[u] then l[u]:=l[v]; {u的儿子v的关联边全部被访问时,l[u]=min(l[u],l[v])}
{!!!} {G[u,v]:=-G[u,v]; {恢复(u,v)可访问,对于有向图,请把此行删去}
end;
gray: begin
EdgeType[u,v]:=2; {(u,v)为反向边}
if d[v]<l[u] then l[u]:=d[v]; {访问反向边(u,v)时,l[u]:=min(l[u],d[v])}
end;
black: begin
if d[v]>d[u] then EdgeType[u,v]:=3 {(u,v)为正向边}
else EdgeType[u,v]:=4; {(u,v)为交叉边}
end;
end; {end of case}
c[u]:=black;
inc(time);
f[u]:=time;
end;

procedure Print;
var
i,j:integer;
begin
writeln(fout,'Edge Type:');
for i:=1 to size do
for j:=1 to size do
case EdgeType[i,j] of
1: writeln(fout,i,' ',j,' ','树枝边');
2: writeln(fout,i,' ',j,' ','反向边');
3: writeln(fout,i,' ',j,' ','正向边');
4: writeln(fout,i,' ',j,' ','交叉边');
end;
writeln(fout,'d:');
for i:=1 to size do writeln(fout,d[i]);
writeln(fout,'f:');
for i:=1 to size do writeln(fout,f[i]);
writeln(fout,'p:');
for i:=1 to size do writeln(fout,p[i]);
writeln(fout,'b:');
for i:=1 to size do writeln(fout,b[i]);
writeln(fout,'l:');
for i:=1 to size do writeln(fout,l[i]);
end;

begin
fillchar(c,sizeof(c),white);
fillchar(p,sizeof(p),0);
fillchar(b,sizeof(b),0);
time:=0;
for u:=1 to size do
if c[u]=white then DFS_visit(u);
Print;
end;

procedure main;
var i,j,k:integer;
begin
//insert your codes
writeln(fout,'Case ',probN);
DFS(G,n);

//end your codes here
end;

begin
assign(fin,infile); reset(fin);
assign(fout,outfile); rewrite(fout);
probN:=0;
while init do main;
close(fin); close(fout);
end;

begin
fundament;
end.

starfish 2001-08-23
  • 打赏
  • 举报
回复
只要用深度优先搜索,找到不属于任何简单回路的边,那条边就是桥。
在深度优先搜索时通过标号对边进行分类,如果搜索到一条树枝边(U,V)时发现V及V的后代不存在一条连接U的祖先的反向边,则边(U,V)就是桥

33,007

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧