算法与数据结构答案第7章图.docx
《算法与数据结构答案第7章图.docx》由会员分享,可在线阅读,更多相关《算法与数据结构答案第7章图.docx(26页珍藏版)》请在冰豆网上搜索。
算法与数据结构答案第7章图
第7章图
一、基础知识题
7.1设无向图的顶点个数为n,则该图最多有多少条边?
【解答】n(n-1)/2
7.2一个n个顶点的连通无向图,其边的个数至少为多少?
【解答】n-1
7.3要连通具有n个顶点的有向图,至少需要多少条弧?
【解答】n
7.4n个顶点的完全有向图含有弧的数目是多少?
【解答】n(n-1)
7.5一个有n个顶点的无向图,最少有多少个连通分量,最多有多少个连通分量。
【解答】1,n
7.6图的BFS生成树的树高要小于等于同图DFS生成树的树高,对吗?
【解答】对
7.7无向图G=(V,E),其中:
V={a,b,c,d,e,f},E={(a,b),(a,e),(a,c),(b,e),(c,f),(f,d),(e,d)},写出对该图从顶点a出发进行深度优先遍历可能得到的全部顶点序列。
【解答】abedfc,acfdeb,aebdfc,aedfcb
7.8在图采用邻接表存储时,求最小生成树的Prim算法的时间复杂度是多少?
【解答】O(n+e)
7.9若一个具有n个顶点,e条边的无向图是一个森林,则该森林中必有多少棵树?
【解答】n-e
7.10n个顶点的无向图的邻接矩阵至少有多少非零元素?
【解答】0
7.11证明:
具有n个顶点和多于n-1条边的无向连通图G一定不是树。
【证明】具有n个顶点n-1条边的无向连通图是自由树,即没有确定根结点的树,每个结点均可当根。
若边数多于n-1条,因一条边要连接两个结点,则必因加上这一条边而使两个结点多了一条通路,即形成回路。
形成回路的连通图不再是树。
7.12证明对有向图顶点适当编号,使其邻接矩阵为下三角形且主对角线为全零的充要条件是该图是无环图。
【证明】该有向图顶点编号的规律是让弧尾顶点的编号大于弧头顶点的编号。
由于不允许从某顶点发出并回到自身顶点的弧,所以邻接矩阵主对角元素均为0。
先证明该命题的充分条件。
由于弧尾顶点的编号均大于弧头顶点的编号,在邻接矩阵中,非零元素(A[i][j]=1)自然是落到下三角矩阵中;命题的必要条件是要使上三角为0,则不允许出现弧头顶点编号大于弧尾顶点编号的弧,否则,就必然存在环路。
(对该类有向无环图顶点编号,应按顶点出度的大小进行顺序编号。
)
7.13设G=(V,E)以邻接表存储,如图所示,试画出从顶点1出发所得到的深度优先和广度优先生成树。
习题7.13的图
【解答】深度优先生成树
1
2
3
4
5
宽度优先生成树:
1
2
3
4
5
7.14已知一个图的顶点集V和边集E分别为:
V={0,1,2,3,4,5,6,7};
E={<0,2>,<1,3>,<1,4>,<2,4>,<2,5>,<3,6>,<3,7>,<4,7>,<4,8>,<5,7>,<6,7>,<7,8>};
若存储它采用邻接表,并且每个顶点邻接表中的边结点都是按照顶点序号从小到大的次序链接的,则按教材中介绍的进行拓扑排序的算法,写出得到的拓扑序列。
【解答】1-3-6-0-2-5-4-7-8
7.15一带权无向图的邻接矩阵如下图,试画出它的一棵最小生成树。
习题7.15的图
习题7.16的图
【解答】设顶点集合为{1,2,3,4,5,6},
由下边的逻辑图可以看出,在{1,2,3}和{4,5,6}回路中,
各任选两条边,加上(2,4),则可构成9棵不同的最小生成树。
1
2
1
1
1
1
1
3
1
2
3
4
5
6
7.16如图所示是一带权有向图的邻接表法存储表示。
其中出边表中的每个结点均含有三个字段,依次为边的另一个顶点在顶点表中的序号、边上的权值和指向下一个边结点的指针。
试求:
(1).该带权有向图的图形;
(2).从顶点V1为起点的广度优先遍历的顶点序列及对应的生成树;
(3).以顶点V1为起点的深度优先遍历生成树;
(4).由顶点V1到顶点V3的最短路径。
33
36
25
18
10
29
38
30
42
1
4
3
2
6
5
【解答】
(1)
(2)V1,V2,V4,V6,V3,V5
1
2
4
6
3
5
(3) 顶点集合V(G)={V1,V2,V3,V4,V5,V6}
边的集合E(G)={,,,,}
(4) V1到V3最短路径为67:
(V1—V4—V3)
迭代
集合S
选择
顶点
D[]
D[2]D[3]D[4]D[5]D[6]
初值
{v1}
33∞29∞25
1
{v1,v6}
v6
33∞29∞25
2
{v1,v6,v4}
v4
33672971
3
{v1,v6,v4,v2}
v2
336771
4
{v1,v6,v4,v2,v3}
v3
6771
5
{v1,v6,v4,v2,v3,v5}
v
71
7.17已知一有向网的邻接矩阵如下,如需在其中一个顶点建立娱乐中心,要求该顶点距其它各顶点的最长往返路程最短,相同条件下总的往返路程越短越好,问娱乐中心应选址何处?
给出解题过程。
习题7.18的图
习题7.17的图
【解答】下面用FLOYD算法求出任意两顶点的最短路径(如图A(6)所示)。
题目要求娱乐中心“距其它各结点的最长往返路程最短”,结点V1,V3,V5和V6最长往返路径最短都是9。
按着“相同条件下总的往返路径越短越好”,选顶点V5,总的往返路径是34。
A(0)=A
(1)=A
(2)=A(3)=A(4)=A(5)=A(6)=
7.18求出图中顶点1到其余各顶点的最短路径。
【解答】本表中DIST中各列最下方的数字是顶点1到顶点的最短通路。
所选顶点
S(已确定最短路径
的顶点集合)
T(尚未确定最短
路径的顶点集合)
DIST
[2]
[3]
[4]
[5]
[6]
[7]
[8]
初态
{1}
{2,3,4,5,6,7,8}
30
∞
60
10
∞
∞
∞
5
{1,5}
{2,3,4,6,7,8}
25
∞
60
10
17
∞
∞
6
{1,5,6}
{2,3,4,7,8}
20
33
60
17
25
∞
2
{1,5,6,2}
{3,4,7,8}
20
33
60
25
∞
7
{1,5,6,2,7}
{3,4,8}
31
28
25
35
4
{1,5,6,2,7,4}
{3,8}
31
28
35
3
{1,5,6,2,7,4,3}
{5,8}
31
35
8
{1,5,6,2,7,4,3,8}
{8}
35
顶点1到其它顶点的最短路径依次是20,31,28,10,17,25,35。
按Dijkstra算法所选顶点依次是5,6,2,7,4,3,8。
7.19对图示的AOE网络,计算各活动弧的e(ai)和l(ai)的函数值,各事件(顶点)的ve(vi)和vl(vi)的函数值,列出各条关键路径。
【解答】
顶点
α
A
B
C
D
E
F
G
H
W
Ve(i)
0
1
6
3
4
24
13
39
22
52
Vl(i)
0
29
24
3
7
31
13
39
22
52
活动
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10
a11
a12
a13
a14
a15
a16
a17
e(i)
0
0
0
0
1
6
6
3
3
4
24
13
13
13
39
22
22
l(i)
28
18
0
3
29
24
31
34
3
7
31
20
36
13
39
22
40
α
C
F
H
G
W
,长52。
关键路径是:
活动与顶点的对照表:
a1<α,A>a2<α,B>a3<α,C>a4<α,D>a5a6a7a8
a9a10a11a12a13a14a15a16a17
7.20 利用弗洛伊德算法,写出如图所示相应的带权邻接矩阵的变化。
3
2
1
4
5
9
6
8
2
3
1
10
【解答】A0=A1=A2=A3=A4=
二、算法设计题
7.21设无向图G有n个顶点,m条边。
试编写用邻接表存储该图的算法。
voidCreatGraph(AdjListg)∥建立有n个顶点和m条边的无向图的邻接表存储结构
{intn,m;
scanf("%d%d",&n,&m);
for(i=0,i{scanf(&g[i].vertex);g[i].firstarc=null;}
for(k=0;k{scanf(&v1,&v2);∥输入两个顶点
i=GraphLocateVertex(g,v1);j=GraphLocateVertex(g,v2);∥顶点定位
p=(ArcNode*)malloc(sizeof(ArcNode));∥申请边结点
p->adjvex=j;p->next=g[i].firstarc;g[i].firstarc=p;∥将边结点链入
p=(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex=i;p->next=g[j].firstarc;g[j].frstarc=p;
}∥for
}∥算法CreatGraph结束
7.22已知有向图有n个顶点,请编写算法,根据用户输入的偶对建立该有向图的邻接表。
voidCreatAdjList(AdjListg)∥建立有向图的邻接表存储结构
{intn;
scanf("%d",&n);
for(i=0;i{scanf(&g[i].vertex);g[i].firstarc=null;}∥输入顶点信息,下标从0开始
scanf(&v1,.&v2);
while(v1&&v2)∥题目要求两顶点之一为0表示结束
{i=GraphLocateVertex(g,v1);
p=(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex=j;p->next=g[i].firstarc;g[i].firstarc=p;
scanf(&v1,&v2);
}∥while
}
7.23给出以十字链表作存储结构,建立图的算法,输入(i,j,v)其中i,j为顶点号,v为权值。
voidCreatOrthList(OrthListg)∥建立有向图的十字链表存储结构
{inti,j,v;∥假定权值为整型
scanf("%d",&n);
for(i=0,i{scanf(&g[i].vertex);g[i].firstin=null;g[i].firstout=null;}
scanf("%d%d%d",&i,&j,&v);
while(i&&j&&v)∥当输入i,j,v之一为0时,结束算法运行
{p=(OrArcNode*)malloc(sizeof(OrArcNode));∥申请结点
p->headvex=j;p->tailvex=i;p->weight=v;∥弧结点中权值域
p->headlink=g[j].firstin;g[j].firstin=p;
p->tailink=g[i].firstout;g[i].firstout=p;
scanf("%d%d%d",&i,&j,&v);
}∥while
}∥算法结束
[算法讨论]本题已假定输入的i和j是顶点号,否则,顶点的信息要输入,且用顶点定位函数求出顶点在顶点向量中的下标。
图建立时,若已知边数(如上面1和2题),可以用for循环;若不知边数,可用while循环(如本题),规定输入特殊数(如本题的零值)时结束运行。
本题中数值设为整型,否则应以和数值类型相容的方式输入。
7.24设有向图G有n个点(用1,2,…,n表示),e条边,写一算法根据G的邻接表生成G的反向邻接表,要求算法时间复杂性为O(n+e)。
voidInvertAdjList(AdjListgin,gout)∥将有向图的出度邻接表改为按入度建立的逆邻接表
{for(i=0;i{gin[i].vertex=gout[i].vertex;gin[i].firstarc=null;}
for(i=0;i{p=gout[i].firstarc;∥取指向邻接点的指针
while(p!
=null)
{j=p->adjvex;
s=(ArcNode*)malloc(sizeof(ArcNode));∥申请结点空间
s->adjvex=i;s->next=gin[j].firstarc;gin[j].firstarc=s;
p=p->next;∥下一个邻接点。
}∥while
}∥for
}
7.25写出从图的邻接表表示转换成邻接矩阵表示的算法。
voidAdjListToAdjMatrix(AdjListgl,AdjMatrixgm)
∥将图的邻接表表示转换为邻接矩阵表示
{for(i=0;ifor(j=0;jfor(i=0;i{p=gl[i].firstarc;
while(p!
=null)
{gm[i][p->adjvex]=1;p=p->next;}
}∥for
}∥算法结束
7.26试写出把图的邻接矩阵表示转换为邻接表表示的算法。
voidAdjMatrixToAdjList(AdjMatrixgm,AdjListgl)
∥将图的邻接矩阵表示转换为邻接表表示
{for(i=0;i{scanf(&gl[i].vertex);gl[i].firstarc=null;}
for(i=0;ifor(j=0;jif(gm[i][j]==1)
{p=(ArcNode*)malloc(sizeof(ArcNode));∥申请结点空间
p->adjvex=j;∥顶点I的邻接点是j
p->next=gl[i].firstarc;
gl[i].firstarc=p;∥链入顶点i的邻接点链表中
}∥if
}∥end
7.27试编写建立有n个顶点,m条边且以邻接多重表为存储结构表示的无向图的算法。
voidCreatMGraph(AdjMulistg)
∥建立有n个顶点e条边的无向图的邻接多重表的存储结构
{intn,e;
scanf("%d%d",&n,&e);
for(i=0,i{scanf(&g[i].vertex);g[i].firstedge=null;}
for(k=0;k{scanf(&v1,&v2);
i=GraphLocateVertex(g,v1);j=GraphLocateVertex(g,v2);
p=(ENode*)malloc(sizeof(ENode));
p->ivex=i;p->jvex=j;
p->ilink=g[i].firstedge;p->jlink=g[j].firstedge;
g[i].firstedge=p;g[j].firstedge=p;
}∥for
}∥算法结束
7.28已知某有向图(n个结点)的邻接表,求该图各结点的入度数。
【题目分析】在有向图的邻接表存储结构中求顶点的入度,需要遍历整个邻接表。
voidIndegree(AdjListg)∥求以邻接表为存储结构的n个顶点有向图的各顶点入度
{for(i=0;i{num=0;∥入度初始为0
for(j=0;jif(i!
=j)
{p=g[j].firstarc;
while(p)
{if(p->adjvex==i)num++;p=p->next;}
}
printf(“顶点%d的入度为:
%d\n”,g[i].vexdata,num);∥设顶点数据为整型
}
}
7.29已知无向图G=(V,E),给出求图G的连通分量个数的算法。
【题目分析】使用图的遍历可以求出图的连通分量。
进入dfs或bfs一次,就可以访问到图的一个连通分量的所有顶点。
voiddfs(v)
{visited[v]=1;printf(“%3d”,v);∥输出连通分量的顶点。
p=g[v].firstarc;
while(p!
=null)
{if(visited[p->adjvex==0])dfs(p->adjvex);
p=p->next;
}∥while
}∥dfs
voidCount()
∥求图中连通分量的个数
{intk=0;staticAdjListg;∥设无向图g有n个结点
for(i=0;iif(visited[i]==0){printf("\n第%d个连通分量:
\n",++k);dfs(i);}∥if
}∥Count
【算法讨论】算法中visited[]数组是全程变量,每个连通分量的顶点集按遍历顺序输出。
这里设顶点信息就是顶点编号,否则应取其g[i].vertex分量输出。
7.30已知无向图采用邻接表存储方式,试写出删除边(i,j)的算法。
voidDeletEdge(AdjListg,inti,j)
∥在用邻接表方式存储的无向图g中,删除边(i,j)
{p=g[i].firstarc;pre=null;∥删顶点i的边结点(i,j),pre是前驱指针
while(p)
if(p->adjvex==j)
{if(pre==null)g[i].firstarc=p->next;
elsepre->next=p->next;free(p);
}∥释放空间
else{pre=p;p=p->next;}∥沿链表继续查找
p=g[j].firstarc;pre=null;∥删顶点j的边结点(j,i)
while(p)
if(p->adjvex==i)
{if(pre==null)g[j].firstarc=p->next;
elsepre->next=p->next;free(p);
}∥释放空间
else{pre=p;p=p->next;}∥沿链表继续查找
}∥DeletEdge
【算法讨论】算法中假定给的i,j均存在,否则应检查其合法性。
若未给顶点编号,而给出顶点信息,则先用顶点定位函数求出其在邻接表顶点向量中的下标i和j。
7.31假设有向图以邻接表存储,试编写算法删除弧的算法。
voidDeleteArc(AdjListg,vertypevi,vj)
∥删除以邻接表存储的有向图g的一条弧,假定顶点vi和vj存在
{i=GraphLocateVertex(g,vi);
j=GraphLocateVertex(g,vj);∥顶点定位
p=g[i].firstarc;pre=null;
while(p)
if(p->adjvex==j)
{if(pre==null)g[i].firstarc=p->next;
elsepre->next=p->next;free(p);
}∥释放结点空间
else{pre=p;p=p->next;}
}∥结束
7.32 设计一个算法利用遍历图的方法判别一个有向图G中是否存在从顶点Vi到Vj的长度为k的简单路径,假设有向图采用邻接表存储结构。
【题目分析】本题利用深度优先递归的搜索方法判断有向图G的顶点i到j是否存在长度为k的简单路径,先找到i的第一个邻接点m,再从m出发递归的求是否存在m到j的长度为k-1的简单路径。
intexistpathlen(AlGraphG,inti,intj,intk)
{//判断邻接表方式存储的有向图G的顶点i到j是否存在长度为k的简单路径
if(i==j&&k==0)return1;//找到了一条路径,且长度符合要求
elseif(k>0)
{visited[i]=1;
for(p=G.vertices[i].firstarc;p;p=p->next)
{m=p->adjvex;
if(!
visited[m])
if(existpathlen(G,m,j,k-1))return1;//剩余路径长度减一
}
visited[i]=0;//本题允许曾经被访问过的结点出现在另一条路径中
}
return0;//没找到
}
7.33 设有向图G采用邻接矩阵存储,编写算法求出G中顶点i到顶点j的不含回路的、长度为k的路径数。
intGetPathNum(AdjMatrixGA,inti,intj,intk,intn)
{//求邻接矩阵方式存储的有向图G的顶点i到j之间长度为k的简单路径条数
//n为顶点个数
if(i==j&&k==0)return1;//找到了一条路径,且长度符合要求
elseif(k>0)
{sum=0;//sum表示通过本结点的路径数
visited[i]=1;
for(k=0;k{if(GA[i][k]!
=0&&!
visited[k])
sum+=GetPathNum(GA,k,j,k-1,n)//剩余路径长度减一
}
visited[i]=0;//本题允许曾经被访问过的结点出现在另一条路径中
}
returnsum;
}
7.34 设计算法求出以邻接表存储的有向图G中由顶点u到v的所有的简单路径。
voidAllSPdfs(AdjL