图 练习 1

转载自:https://mp.weixin.qq.com/s/jkWcTwLV9tH8yfOjnzaE9A

初步说明:图论中的词汇差异很大。一些作者使用相同的词具有不同的含义。有些作者用不同的词来表示同一件事。我希望我们的定义没有矛盾。

 

图被定义为一组节点和一组边,其中每个边是一对节点。

在Prolog中有几种表示图的方法。

 

一种方法是将每个边分别表示为一个子句(事实)。以这种形式,相应的图表示为以下谓词:

 

    edge(h,g).

    edge(k,f).

    edge(f,b).   

    ...

我们称此edge-clause

 

显然,独立的节点无法表示。另一种方法是将整个图表示为一个数据对象。根据图的定义为两个集合对(节点和边),我们可以使用以下Prolog项来表示上述示例图:

graph([b,c,d,f,g,h,k],[e(b,c),e(b,f),e(c,f),e(f,k),e(g,h)])

我们称这种图项形式。注意,列表保持排序,它们实际上是集合,没有重复的元素。每个边在边列表中仅出现一次;即,从一个节点x到另一个节点y的边表示为e(x,y),则不存在项e(y,x)。图项形式是我们的默认表示形式。 在SWI-Prolog中,有预定义的谓词可用于集合。

 

第三种表示方法是与每个节点关联与该节点相邻的节点集。我们称其为 邻接列表形式。在我们的示例中:

[n(b,[c,f]), n(c,[b,f]), n(d,[]), n(f,[b,c,k]), ...]

到目前为止,我们介绍的表示形式都是Prolog项,因此非常适合自动化处理,但是它们的语法不是非常用户友好。手工输入这些项很麻烦且容易出错。我们可以定义一个更紧凑和“对人类友好(human-friendly)”的表示法,如下所示:图由X-Y类型的原子和项(即函子’-‘和arity 2)的列表表示。原子代表独立的节点,X-Y项描述边。如果X出现为边的端节点,则会自动将其定义为节点。我们的示例可以写成:

[b-c, f-c, g-h, d, f-b, k-f, h-g]

我们称其为人类友好的形式(human-friendly)。如示例所示,列表不必排序,甚至可以多次包含相同的边。注意独立节点d。(实际上,在Prolog的意义上,独立的节点甚至不必是原子,它们可以是复合项,例如d(3.75,blue)而不是示例中的d)。

当边有指向后,我们称其为弧(arc)。这些由有序对表示。这样的图称为有向图(digraph)。为了表示有向图,对上面讨论的形式进行了一些修改。相应的示例图如下所示:

Arc-clause形式

arc(s,u).

arc(u,r).

...

 

 

图项(Graph-term)形式

digraph([r,s,t,u,v],[a(s,r),a(s,u),a(u,r),a(u,s),a(v,u)])

 

邻接表(adjacency-list)

[n(r,[]),n(s,[r,u]),n(t,[]),n(u,[r,s]),n(v,[u])]

请注意,邻接表(adjacency-list)没有有关它是图还是有向图的信息。

 

人性化形式

[s > r, t, u > r, s > u, u > s, v > u]

最后,图和有向图可能具有附加到节点和边(弧)的附加信息。对于节点而言,这没有问题,因为我们可以轻松地用任意复合词替换单个字符标识符,例如city(’London’,4711)。另一方面,对于边,我们必须扩展符号。在边上附加了附加信息的称为标记图

Arc-clause形式

    arc(m,q,7).

    arc(p,q,9).

    arc(p,m,5).

 

图项形式

digraph([k,m,p,q],[a(m,p,7),a(p,m,5),a(p,q,9)])

 

邻接表

[n(k,[]),n(m,[q/7]),n(p,[m/5,q/9]),n(q,[])]

请注意边缘信息的状态与函子“ /”和arity 2以及相应的节点一起打包到一个术语中。

 

人性化形式

[p>q/9, m>q/7, k, p>m/5]

带标签图的符号也可用于所谓的 多图,其中两个给定节点之间允许有多个边(或弧)。

 

1、图表示之间的转换

 

编写谓词以在不同的图表示形式之间进行转换。使用这些谓词,所有表示都是等效的。即对于以下问题,您始终可以自由选择最方便的格式(form)。

 

我们使用以下符号:

邻接表  adjacency-list (alist): [n(b,[c,g,h]), n(c,[b,d,f,h]), n(d,[c,f]), …] 

图项  graph-term (gterm)  graph([b,c,d,f,g,h,k],[e(b,c),e(b,g),e(b,h), ...]) 或 digraph([r,s,t,u],[a(r,s),a(r,t),a(s,t), …]) 

边子句  edge-clause(ecl): edge(b,g).  (程序内数据库)

弧子句  arc-clause (acl):  arc(r,s).   (程序内数据库)  

人性化   human-friendly (hf): [a-b,c,g-h,d-e]  或 [a>b,h>g,c,b>a]

主要的转换谓词是:alist_gterm/3和human_gterm/2,这两个谓词(希望)都可以在任意方向上工作,也可以用于图和有向图,无论是否标记。

alist_gterm(Type,AL,GT) :- 在邻接表和图项表示之间进行转换。类型是“图”或“有向图”。

(atom,alist,gterm)  (+,+,?) or (?,?,+)

 

 

  alist_gterm(Type,AL,GT):- 

2 nonvar(GT), 

3 !, 

4 gterm_to_alist(GT,Type,AL).

5   alist_gterm(Type,AL,GT):- 

6 atom(Type), 

7 nonvar(AL), 

8 alist_to_gterm(Type,AL,GT).

9

行注释:

1.  原子列表与图项互转

2.  确保GT为非变量

3.  截断

4.  图项转为原子列表

5.  原子列表与图项互转

6.  确保Type为非变量

7.  确保AL为非变量

8.  原子列表转为图项

9.  空行

 

10  gterm_to_alist(graph(Ns,Es),graph,AL) :- 

11 memberchk(e(_,_,_),Es), 

12 ! ,

13 lgt_al(Ns,Es,AL).

14  gterm_to_alist(graph(Ns,Es),graph,AL) :- 

15 !, 

16 gt_al(Ns,Es,AL).

17  gterm_to_alist(digraph(Ns,As),digraph,AL) :- 

18 memberchk(a(_,_,_),As), !,

19 ldt_al(Ns,As,AL).

20  gterm_to_alist(digraph(Ns,As),digraph,AL) :- 

21 dt_al(Ns,As,AL).

22

行注释:

10. 图项转换为原子列表

11. 内部谓词,检查参数1是否在参数2的列表中

12. 截断

13. 标记图列表转为原子列表

14. 图项转换为原子列表

15. 截断

16. 无标记图列表转为原子列表

17. 有向图项转换为原子列表

18. 内部谓词,检查参数1是否在参数2的列表中

19. 标记有向图列表转为原子列表

20. 有向图项转换为原子列表

21. 无标记有向图列表转为原子列表

22. 空行

 

23  % 标记图

24  lgt_al([],_,[]).

25  lgt_al([V|Vs],Es,[n(V,L)|Ns]) :-

26 findall(T,((member(e(X,V,I),Es) ; 

27             member(e(V,X,I),Es)),T = X/I),L),

28 lgt_al(Vs,Es,Ns).

29

行注释:

24. 递归终止条件

25. 

26. findall是内部谓词的参阅高阶谓词 符号‘;’为或运算符

27. member内部谓词,将X/I的值T放入列表L中

28. 继续递归

29. 空行

 

30  % 无标记图

31  gt_al([],_,[]).

32  gt_al([V|Vs],Es,[n(V,L)|Ns]) :-

33 findall(X,(member(e(X,V),Es) ; 

34 member(e(V,X),Es)),L), 

35 gt_al(Vs,Es,Ns).

36

行注释:

31. 终止条件

32. 

33. findall是内部谓词的参阅高阶谓词 符号‘;’为或运算符

34. member内部谓词,将X的值放入列表L中

35. 继续递归

36. 空行

 

37  % 标记有向图

38  ldt_al([],_,[]).

39  ldt_al([V|Vs],As,[n(V,L)|Ns]) :-

40 findall(T,(member(a(V,X,I),As), T=X/I),L), 

41 ldt_al(Vs,As,Ns).

42

行注释:

38. 终止条件

39. 

40. findall是内部谓词的参阅高阶谓词 member内部谓词,将X/I的值T放入列表L中

41. 继续递归

42. 空行

 

43  % 无标记有向图

44  dt_al([],_,[]).

45  dt_al([V|Vs],As,[n(V,L)|Ns]) :-

46 findall(X,member(a(V,X),As),L), 

47 dt_al(Vs,As,Ns).

48

行注释:

43. 

44. 终止条件

45. 

46. findall是内部谓词的参阅高阶谓词 member内部谓词,将X的值放入列表L中

47. 继续递归

48. 空行

 

49  alist_to_gterm(graph,AL,graph(Ns,Es)) :- 

50 !, 

51 al_gt(AL,Ns,EsU,[]), 

52 sort(EsU,Es).

53  alist_to_gterm(digraph,AL,digraph(Ns,As)) :- 

54 al_dt(AL,Ns,AsU,[]), 

55 sort(AsU,As).

56

行注释:

49. 原子列表转换为图项(无向图)

50. 截断

51. 将AL转为Ns和EsU

52. 列表Es是列表EsU排序后的结果

53. 原子列表转换为图项(有向图)

54. 将AL转为Ns和AsU

55. 列表As是列表AsU排序后的结果

56. 空行

 

57  al_gt([],[],Es,Es).

58  al_gt([n(V,Xs)|Ns],[V|Vs],Es,Acc) :- 

59 add_edges(V,Xs,Acc1,Acc), 

60 al_gt(Ns,Vs,Es,Acc1). 

61

行注释:

57. 终止条件

58. 将参数1转为参数2和参数3

59. 增加边

60. 继续递归

61. 空行

 

62  add_edges(_,[],Es,Es).

63  add_edges(V,[X/_|Xs],Es,Acc) :- 

64 V @> X

65 !, 

66 add_edges(V,Xs,Es,Acc).

67  add_edges(V,[X|Xs],Es,Acc) :- 

68 V @> X

69 !, 

70 add_edges(V,Xs,Es,Acc).

71  add_edges(V,[X/I|Xs],Es,Acc) :- 

72 V @=< X

73 !, 

74 add_edges(V,Xs,Es,[e(V,X,I)|Acc]).

75  add_edges(V,[X|Xs],Es,Acc) :- 

76 V @=< X

77 add_edges(V,Xs,Es,[e(V,X)|Acc]).

78

行注释:

62. 终止条件

63. 满足第二个参数列表中[X/_|Xs]表首X后有’/‘符号时

64. 项V大于项X

65. 截断

66. 继续递归

67. 

68. 项V大于项X

69. 截断

70. 继续递归

71. 满足第二个参数列表中[X/I|Xs]表首X后有’/‘符号时

72. 项V小于等于项X

73. 截断

74. 将项’e(V,X,I)’加入参数4列表的表首后继续递归

75. 

76. 项V小于等于项X

77. 将项’e(V,X)’加入参数4列表的表首后继续递归

78. 空行

 

79  al_dt([],[],As,As).

80  al_dt([n(V,Xs)|Ns],[V|Vs],As,Acc) :- 

81 add_arcs(V,Xs,Acc1,Acc), 

82 al_dt(Ns,Vs,As,Acc1). 

83

行注释:

79. 终止条件

80. 原子列表转为有向图

81. 增加弧

82. 继续递归

83. 空行

 

84  add_arcs(_,[],As,As).

85  add_arcs(V,[X/I|Xs],As,Acc) :- 

86 !, 

87 add_arcs(V,Xs,As,[a(V,X,I)|Acc]).

88  add_arcs(V,[X|Xs],As,Acc) :- 

89 add_arcs(V,Xs,As,[a(V,X)|Acc]).

90

91  % 

92

93  % ecl_to_gterm(GT) :-

94  %从程序数据库中的edge/2事实构造一个图项。

95

行注释:

84. 终止条件

85. 第二参数列表X后有符号’/’时

86. 截断

87. 参数4列表首增加项a(V,X,I)继续递归

88. 

89. 参数4列表首增加项a(V,X)继续递归

90~95. 注释

96  ecl_to_gterm(GT) :-

97 findall(E,(edge(X,Y),E=X-Y),Es), 

98 human_gterm(Es,GT).

99

100 % acl_to_gterm(GT) :-

101 % 从程序数据库中的arc/2事实构造图项

102

103 acl_to_gterm(GT) :-

104 findall(A,(arc(X,Y),A= >(X,Y)),As), 

105 human_gterm(As,GT).

106

107 % ---------------------------------------------------------------------------

108 

109 % human_gterm(HF,GT) :- 在人类友好和图项表示之间转换。

110 

111 %    (list,gterm) (+,?) or (?,+)

112

行注释:

96. 从程序数据库中的edge/2事实构造图项

97. 搜索所有边edge(X,Y)的解集使得E=X-Y,将E的值放入列表Es

98. 将Es转为GT

99. 空行

100~102. 注释

103. 从程序数据库中的arc/2事实构造图项

104. 搜索所有弧arc(X,Y)的解集使得A= >(X-Y),将A的值放入列表As

105. 将As转为GT

106~112. 注释

 

 

113 human_gterm(HF,GT):- 

114 nonvar(GT), 

115 !, 

116 gterm_to_human(GT,HF).

117 human_gterm(HF,GT):- 

118 nonvar(HF), 

119 human_to_gterm(HF,GT).

120

行注释:

113. 从’图项’GT转换为人类友好表示法HF

114. GT不是变量

115. 截断

116. 从’图项’GT转换为人类友好表示法HF

117. 从人类友好表示法HF转成图项表示法GT

118. HF不是变量

119. 从人类友好表示法HF转成图项表示法GT

120. 空行

 

121 gterm_to_human(graph(Ns,Es),HF) :-  

122 memberchk(e(_,_,_),Es), 

123 !, 

124 lgt_hf(Ns,Es,HF).

125 gterm_to_human(graph(Ns,Es),HF) :-  

126 !, 

127 gt_hf(Ns,Es,HF).

128 gterm_to_human(digraph(Ns,As),HF) :- 

129 memberchk(a(_,_,_),As), 

130 !, 

131 ldt_hf(Ns,As,HF).

132 gterm_to_human(digraph(Ns,As),HF) :- 

133 dt_hf(Ns,As,HF).

行注释:

121. 从’图项’转换为人类友好表示法

122. Es的项是e(_,_,_)

123. 截断

124. 调用标记图项转人类友好

125. 

126. 截断

127. 调用无标记图项转人类友好

128. 从有向’图项’转换为人类友好表示法

129. As的项是a(_,_,_)

130. 截断

131. 调用有标记有向图转人类友好

132. 

133. 调用无标记有向图转人类友好

 

134 % 标记图

135 lgt_hf(Ns,[],Ns).

136 lgt_hf(Ns,[e(X,Y,I)|Es],[X-Y/I|Hs]) :-

137 delete(Ns,X,Ns1),

138 delete(Ns1,Y,Ns2),

139 lgt_hf(Ns2,Es,Hs).

140

行注释:

135. 终止条件

136. 

137. 删除列表Ns中匹配Y值的元素结果放入Ns1

138. 删除列表Ns1中匹配Y值的元素结果放入Ns2

139. 继续递归

140. 空行

 

141 % 无标记图

142 gt_hf(Ns,[],Ns).

143 gt_hf(Ns,[e(X,Y)|Es],[X-Y|Hs]) :-

144 delete(Ns,X,Ns1),

145 delete(Ns1,Y,Ns2),

146 gt_hf(Ns2,Es,Hs).

147

行注释:

142. 终止条件

143. 

144. 删除列表Ns中匹配Y值的元素结果放入Ns1

145. 删除列表Ns1中匹配Y值的元素结果放入Ns2

146. 继续递归

147. 空行

 

148 % 标记有向图

149 ldt_hf(Ns,[],Ns).

150 ldt_hf(Ns,[a(X,Y,I)|As],[X>Y/I|Hs]) :-

151 delete(Ns,X,Ns1),

152 delete(Ns1,Y,Ns2),

153 ldt_hf(Ns2,As,Hs).

154

行注释:

149. 终止条件

150. 

151. 删除列表Ns中匹配Y值的元素结果放入Ns1

152. 删除列表Ns1中匹配Y值的元素结果放入Ns2

153. 继续递归

154. 空行

 

155 %无标记有向图

156 dt_hf(Ns,[],Ns).

157 dt_hf(Ns,[a(X,Y)|As],[X>Y|Hs]) :-

158 delete(Ns,X,Ns1),

159 delete(Ns1,Y,Ns2),

160 dt_hf(Ns2,As,Hs).

161

行注释:

156. 终止条件

157. 

158. 删除列表Ns中匹配Y值的元素结果放入Ns1

159. 删除列表Ns1中匹配Y值的元素结果放入Ns2

160. 继续递归

161. 空行

 

162 % 我们猜想如果有一个“>”项,那么它就是一个有向图,否则就是一个图

163 human_to_gterm(HF,digraph(Ns,As)) :- 

164 memberchk(_>_,HF), !, 

165 hf_dt(HF,Ns1,As1), 

166 sort(Ns1,Ns), 

167 sort(As1,As).

168 human_to_gterm(HF,graph(Ns,Es)) :- 

169 hf_gt(HF,Ns1,Es1), 

170 sort(Ns1,Ns), 

171 sort(Es1,Es).

172 % 记住:sort/2删除重复项!

173

行注释:

162. 

163. 从人类友好表示法转成有向图项表示法

164. 列表HF的元素满足_>_

165. 调用人类友好转有向图项

166. 排序Ns1到结果集Ns

167. 排序Es1到结果集Es

168. 从人类友好表示法转成图项表示法

169. 调用人类友好转图项

170. 排序Ns1到结果集Ns

171. 排序Es1到结果集Es

172. 单行注释

173. 空行

 

174 hf_gt([],[],[]).

175 hf_gt([X-Y/I|Hs],[X,Y|Ns],[e(U,V,I)|Es]) :- 

176 !, 

177 sort0([X,Y],[U,V]), 

178 hf_gt(Hs,Ns,Es).

179 hf_gt([X-Y|Hs],[X,Y|Ns],[e(U,V)|Es]) :- 

180 !,

181 sort0([X,Y],[U,V]), 

182 hf_gt(Hs,Ns,Es).

183 hf_gt([H|Hs],[H|Ns],Es) :- 

184 hf_gt(Hs,Ns,Es).

185

行注释:

174. 终止条件

175. 人类友好转有标记图项

176. 截断

177. 排序[X,Y],解集为[U,V]

178. 继续递归

179. 人类友好转无标记图项

180. 截断

181. 排序[X,Y],解集为[U,V]

182. 继续递归

183. 人类友好转只有节点没有边

184. 继续递归

185. 空行

 

186 hf_dt([],[],[]).

187 hf_dt([X>Y/I|Hs],[X,Y|Ns],[a(X,Y,I)|As]) :- 

188 !, 

189 hf_dt(Hs,Ns,As).

190 hf_dt([X>Y|Hs],[X,Y|Ns],[a(X,Y)|As]) :- 

191 !,

192 hf_dt(Hs,Ns,As).

193 hf_dt([H|Hs],[H|Ns],As) :-  

194 hf_dt(Hs,Ns,As).

195

行注释:

186. 终止条件

187. 人类友好转有标记有向图

188. 截断

189. 继续递归

190. 人类友好转无标记有向图

191. 截断

192. 继续递归

193. 人类友好转有向图只有节点没有弧

194. 继续递归

195. 空行

 

196 sort0([X,Y],[X,Y]) :- 

197 X @=< Y

198 !.

199 sort0([X,Y],[Y,X]) :- 

200 X @> Y.

201

行注释:

196. 排序

197. X小于等于Y,参数1中列表的顺序不变匹配参数2

198. 截断

199. 将参数1中列表的顺序交换

200. X大于Y

201. 空行

 

202 % tests ------------------------------------------------------------------

203

204 testdata([b-c,f-c,g-h,d,f-b,k-f,h-g]).

205 testdata([s>r,t,u>r,s>u,u>s,v>u]).

206 testdata([b-c/5,f-c/9,g-h/12,d,f-b/13,k-f/3,h-g/7]).

207 testdata([p>q/9,m>q/7,k,p>m/5]).

208 testdata([a,b(4711),c]).

209 testdata([a-b]).

210 testdata([]).

211

212 test :- 

213 testdata(H1),

214 write(H1), nl,

215 human_gterm(H1,G1),

216 alist_gterm(Type,AL,G1), 

217 alist_gterm(Type,AL,G2),

218 human_gterm(H2,G2),

219 human_gterm(H2,G1),

220 write(G1), nlnl,

221 fail.

222 test.

行注释:

212. 

213. 初始化测试用数据

214. 打印输出测试数据H1

215. 从人类友好表示法H1转成图项表示法G1

216. 从图项表示法G1转换和识别为原子列表和类型

217. 从原子列表和类型转换为’图项’(两个方向都可以互转)

218. 从’图项’转换为人类友好表示法H2

219. 从人类友好表示法H2转换为’图项’(两个方向都可以互转)

220. 输出’图项’

221. 强制失败回溯

222. 

 

?- test.

[b-c,f-c,g-h,d,f-b,k-f,h-g]

graph([b,c,d,f,g,h,k],[e(b,c),e(b,f),e(c,f),e(f,k),e(g,h)])

 

graph([b,c,d,f,g,h,k],[e(b,c),e(b,f),e(c,f),e(f,k),e(g,h)])

 

[s>r,t,u>r,s>u,u>s,v>u]

digraph([r,s,t,u,v],[a(s,r),a(s,u),a(u,r),a(u,s),a(v,u)])

 

digraph([r,s,t,u,v],[a(s,r),a(s,u),a(u,r),a(u,s),a(v,u)])

 

[b-c/5,f-c/9,g-h/12,d,f-b/13,k-f/3,h-g/7]

graph([b,c,d,f,g,h,k],[e(b,c,5),e(b,f,13),e(c,f,9),e(f,k,3),e(g,h,7),e(g,h,12)])

 

graph([b,c,d,f,g,h,k],[e(b,c,5),e(b,f,13),e(c,f,9),e(f,k,3),e(g,h,7),e(g,h,12)])

 

[p>q/9,m>q/7,k,p>m/5]

digraph([k,m,p,q],[a(m,q,7),a(p,m,5),a(p,q,9)])

 

digraph([k,m,p,q],[a(m,q,7),a(p,m,5),a(p,q,9)])

 

[a,b(4711),c]

graph([a,c,b(4711)],[])

 

graph([a,c,b(4711)],[])

 

[a-b]

graph([a,b],[e(a,b)])

 

graph([a,b],[e(a,b)])

 

[]

graph([],[])

 

graph([],[])

 

true.

 

?- 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值