我可以用一个方便的谓词来表示这样的点,给我一个更简洁的符号,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