0

平面中点的名称和坐标可以用点 (A, X, Y) 给出。

point(a, 13, 47)在Prolog语言中按照这个关系定义10个点[如],创建一个数据库。

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

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

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

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.

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

4

2 回答 2

0

我可以用一个方便的谓词来表示这样的点,给我一个更简洁的符号,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 个组合成一个列表
  • 用于sort/2对列表进行排序。

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

sort/2此外,由于我们将点的名称作为 outp/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.85081399720322
于 2022-01-25T01:41:51.340 回答
0

,nl,fail.

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

你可以使用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)

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

于 2022-01-20T04:54:33.443 回答