Prolog-获取用坐标绘制的三角形的最大周长



平面中一个点的名称和坐标可以用点(a、X、Y(表示。

根据Prolog语言中的这种关系,通过定义10个点[如point(a, 13, 47)]来创建数据库。

由于其中三个点将定义一个三角形,因此创建列出这些三角形的规则。

通过识别三角形中周长最大的三角形,创建一个在屏幕上打印的规则。

您已经打印了包含关系和规则的程序列表、三角形列表以及周长最大的三角形。

nokta(a, 3,1).
nokta(b, 6,2).
nokta(c, 7,1).
nokta(d, 9,1).
nokta(e, 6,3).
nokta(f, 4,3).
nokta(g, 9,3).
nokta(h, 13, 47).
nokta(i, 15, 49).  
istriangle(A, B, C) :-
A > 0 ,
B > 0 ,
C > 0 ,
A + B >= C ,
A + C >= B ,
B + C >= A .
calculate_the_perimeter_triangle(P1,P2,P3,AB,AC,BC,S) :-
nokta(P1, X1, Y1),
nokta(P2, X2, Y2),
nokta(P3, X3, Y3),
dif(P1, P2),
dif(P2, P3),
dif(P1, P3),
+ (X1 == X2, X2 == X3, X1 == X3),
+ (Y1 == Y2, Y2 == Y3, Y1 == Y3), 
%IABI = √((x2 – x1) ²  + (y2 – y1) ² ) 
AB is sqrt((X2-X1)^2 + (Y2-Y1)^2),
%IACI = √((x3 – x1) ²  + (y3 – y1) ² ) 
AC is sqrt((X3-X1)^2 + (Y3-Y1)^2),
%IBCI = √((x3 – x2) ²  + (y3 – y2) ² )
BC is sqrt((X3-X2)^2 + (Y3-Y2)^2),
S is AB + AC + BC,
AB > 0 ,
AC > 0 ,
BC > 0 .
calculate_perimeter_triangle(N1,N2,N3) :- 
calculate_the_perimeter_triangle(X,Y,Z,N1,N2,N3,S),
istriangle(N1,N2,N3),
write(S - ' Bu koordinatlardan oluşan üçgen.'),
nl,
fail.

我得到了三角形的周长,但我无法得到三角形的周长

我可以用一个方便的谓词来表示这样的点,为我提供一个更简洁的符号p( Name, X:Y )

point( p(N,P) ) :- point(N,P). 
point( a ,   3 :  1 ).
point( b ,   6 :  2 ).
point( c ,   7 :  1 ).
point( d ,   9 :  1 ).
point( e ,   6 :  3 ).
point( f ,   4 :  3 ).
point( g ,   9 :  3 ).
point( h ,  13 : 47 ).
point( i ,  15 : 49 ).

然后可以通过简单地从数据库中绘制3个不同的点来构造三角形。我们可以通过做到这一点

  • 获得每一分
  • 将所有3个集合到一个列表中
  • 使用CCD_ 3对列表进行排序

sort/2通过删除重复元素来确保列表表示集合,这确保了我们不会生成三角形AAB。那只是一条线段。

此外,sort/2,由于我们将点的名称作为p/2结构中的第一个自变量,因此按规范顺序排列点,因此三角形ABC将被认为与三角形CBA相同。

然后,我们使用内置的atom_chars/2谓词,将三个点名称组合为一个原子,以唯一地识别三角形,并计算其周长。

最后,我们将其全部组装成以下形式的t/5结构:

t( Name, Point1, Point2, Point3, perimeter(Perimeter) )

代码如下:

triangle( t(N,Pa,Pb,Pc,perimeter(P)) ) :-
point(P1) ,
point(P2) ,
point(P3) ,
sort([P1,P2,P3],[p(A,Pa),p(B,Pb),p(C,Pc)]) , 
atom_chars(N,[A,B,C]),
perimeter(Pa,Pb,Pc,P) .

计算周长很容易:我们只需计算三角形每条边的长度,然后将它们相加:

perimeter( P1, P2, P3, P ) :-
distance(P1,P2,L1),
distance(P2,P3,L2),
distance(P3,P1,L3),
P is L1+L2+L3
.

计算线段的长度很容易:它只是笛卡尔平面上两点之间的距离,使用勾股定理导出的距离公式:

distance( X1:Y1, X2:Y2, D ) :- D is sqrt( (X2 - X1)^2 + (Y2 - Y1)^2 ).

现在,每个三角形都携带了所需的所有信息。我们可以使用内置的set_of/3谓词收集可以从数据库中的点集构建的三角形集:它对要排序的列表进行排序和去重复:

triangles( Ts ) :- setof( T , triangle(T), Ts ).

剩下的唯一任务是识别周长最长的三角形。这只是递归遍历列表的问题,使用辅助谓词来跟踪周长最长的三角形:

max_perimeter( [T|Ts] , Tmax ) :-
max_perimeter( Ts, T, Tmax ).
max_perimeter( []     , Tmax , Tmax ).
max_perimeter( [T|Ts] , T0   , Tmax ) :-
maxp(T,T0,T1),
max_perimeter(Ts,T1,Tmax).
maxp( T1, T2, T1 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 >= P2, !.
maxp( T1, T2, T2 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 <  P2   .
perimeter( t(_,_,_,_,perimeter(P)) , P ).

然后,我们可以将其与main/0谓词放在一起,以驱动所有内容:

point( p(N,P) ) :- point(N,P).
point( a ,  3: 1  ).
point( b ,  6: 2 ).
point( c ,  7: 1 ).
point( d ,  9: 1 ).
point( e ,  6: 3 ).
point( f ,  4: 3 ).
point( g ,  9: 3 ).
point( h , 13:47 ).
point( i , 15:49 ).
main :-
triangles(Ts)      ,
list_triangles(Ts) ,
max_perimeter(Ts, Tmax),
nl(),
writeln(longest_perimeter) ,
writeln(Tmax).
triangles( Ts ) :- setof( T , triangle(T), Ts ) .
triangle( t(N,Pa,Pb,Pc,perimeter(P)) ) :-
point(P1) ,
point(P2) ,
point(P3) ,
sort([P1,P2,P3],[p(A,Pa),p(B,Pb),p(C,Pc)]) , 
atom_chars(N,[A,B,C]) ,
perimeter(Pa,Pb,Pc,P)
.

perimeter( P1, P2, P3, P ) :-
distance(P1,P2,L1),
distance(P2,P3,L2),
distance(P3,P1,L3),
P is L1+L2+L3
.
distance( X1:Y1, X2:Y2, D ) :- D is sqrt( (X2 - X1)^2 + (Y2 - Y1)^2 ) 
.
list_triangles( [T|Ts] ) :-
writeln(T),
list_triangles(Ts).
list_triangles( []     ).
max_perimeter( [T|Ts] , Tmax ) :-
max_perimeter( Ts, T, Tmax ).
max_perimeter( []     , Tmax , Tmax ).
max_perimeter( [T|Ts] , T0   , Tmax ) :-
maxp(T,T0,T1),
max_perimeter(Ts,T1,Tmax).
maxp( T1, T2, T1 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 >= P2, ! .
maxp( T1, T2, T2 ) :- perimeter(T1,P1), perimeter(T2,P2), P1 <  P2   
.
perimeterf( t(_,_,_,_,perimeter(P)) , P ).

由于您有一个9点的数据集,因此存在9*8*7,或504可能的三角形。运行这表明周长最长的三角形是

  • 三角形:ADI
  • 周长:103.8508139720322

,nl,fail.

这导致calculate_perimeter_triangle失败,Prolog回溯并重试。回溯后,应该就像谓词中的代码从未运行过一样,变量未绑定,状态丢失。只有使用留下副作用(屏幕上的文本(的write(),你才能看到它的发生,但这些信息无法被捕获并保存在程序中。

您可以使用findall/3

findall([nokta(ID1, X1, Y1), nokta(ID2, X2, Y2), nokta(ID3, X3, Y3)],
(
nokta(ID1, X1, Y1), nokta(ID2, X2, Y2), nokta(ID3, X3, Y3),
dif(ID1, ID2), dif(ID2, ID3), dif(ID3, ID1)
),
Triangles)

构建一个列表三角形,其中包含具有不同ID的3xnokta(ID, X, Y)的所有列表,然后使用这些列表来计算周长。

最新更新