【问题标题】:Graphs in PrologProlog 中的图形
【发布时间】:2017-10-06 14:39:09
【问题描述】:

我是 Prolog 的新手,我需要一些帮助:D

我学习了递归并且知道如何使用它(或多或少)。 我在使用图表时遇到问题。我正在尝试解决背包问题,所以我一步一步来。

我的问题: 我有一个类型列表,我想制作长度为 n(=3) 的所有子列表,并选择具有最大价值的一个。我想我需要一个函数来拉出类型列表的头部并将其传递给另一个递归计算“儿子”的函数。我的想法是这样的:

append([],L2,L2):- !.
append([T|C],L2,[T|L3]):-
    append(C,L2,L3).

genera_ext(_,[],_).

genera_ext(Padre,[TT|CT],Figlio):-
    genera(Padre,TT,[TT|CT],Figlio),
    genera_ext(Padre,CT,[]).

genera(Padre,Elem,L_tipi,Figlio):-
    append(Padre,[Elem],Base),
    copy_term(Figlio,Base),
    length(Base,Lun),
    Lun =< 3,
    genera_ext(Base,L_tipi,Temp),
    total_ing(Temp,I_Temp),
    total_ing(Base,I_Base),
    I_Temp >= I_Base,
    copy_term(Figlio,Temp),
    nl,write("Figlio = "),write(Figlio).

genera(_,_,_,_).

显然有问题。你可以帮帮我吗?谢谢 :( 先生。

编辑:

我有一些事实

art(xxx,weight_xxx).

这是计算由元素 xxx 组成的列表的权重的函数

total_ing([],0).
total_ing([X|C],I0):-
    art(X,N),
    total_ing(C,I1),
    I0 is I1 + N.

我叫它

genera_ext([],L_tipi, Figlio)

其中 L_tipi 是我可以选择的元素 xxx 的列表。

我想生成长度为 3 的元素 xxx 的所有可能子列表,并选择权重最大的那个。

【问题讨论】:

  • 你怎么称呼这个?什么是不工作的目标?你能告诉我们你希望做什么吗? total_ing/2 的代码在哪里?

标签: list prolog graph-theory knapsack-problem


【解决方案1】:

我想生成长度为 3 的元素 xxx 的所有可能子列表,并选择权重最大的那个。

这是一个经典的“生成并测试”问题。你可以用一种天真的方式来解决它,通过生成所有可能的艺术排列,像这样:

inefficient([A1,A2,A3], Sum) :-
    art(A1, X),
    art(A2, Y),  A2 \= A1,
    art(A3, Z),  A3 \= A2, A3 \= A1,
    Sum is X+Y+Z.

inefficient_best(L, Sum) :-
    inefficient(L, Sum),
    \+ (inefficient(L2, Sum2), L2 \= L, Sum2 > Sum).

称这种效率低下是非常客气的;它实际上是多次尝试对每个其他排列进行每个排列,并且它将生成多个解决方案,这些解决方案只是排列的相同序列。但它确实“有效”。

接下来要考虑的是如何提高效率。没有明显的事情可以让测试更快,但是生成步骤肯定会创建一堆浪费的组合。我们可以做的第一件事是使用findall/3 将数据库具体化为一个列表,然后使用permutation/2 生成要尝试的排列。但这对我来说感觉就像它一样糟糕。我开始认为最好的方法是制作一个谓词来生成一定长度的组合。我想不出更好的方法来使用内置谓词(也许有一个,我只是不够聪明),但我想出了这个:

combination(0, _, []) :- !.
combination(N, [X|Xs], [X|Ys]) :-
    succ(N0, N),
    combination(N0, Xs, Ys).
combination(N, [_|Xs], Ys) :-
    combination(N, Xs, Ys).

这会产生如下结果:

?- combination(3, [a,b,c,d,e], X).
X = [a, b, c] ;
X = [a, b, d] ;
X = [a, b, e] ;
X = [a, c, d] ;
X = [a, c, e] ;
X = [a, d, e] ;
X = [b, c, d] ;
X = [b, c, e] ;
X = [b, d, e] ;
X = [c, d, e] ;
false.

它的工作方式基本上是要么获取列表中的当前项目并将我们仍然需要的长度减少一,要么重复而不获取当前项目。很像member/2

所以现在我们有了这个,我们可以实现数据库并减少尝试所有排列的工作。事实上,我们可以使用sort/2 来查找获胜者,假设您只需要一个结果,但我们首先需要一个辅助函数:

art_cost(ArtList, Cost-ArtList) :-
    maplist(art, ArtList, CostList),
    sumlist(CostList, Cost).

art_cost/2 计算艺术列表的总成本,但返回一对:与实际艺术列表的成本。这种事情并不少见,我们在下一步中依靠它来为我们的谓词找到最高成本:

best(ArtList, Cost) :-
    % materialize the list of all artworks
    findall(A, art(A,_), Art),

    % materialize the list of candidate combinations
    findall(Candidate, combination(3, Art, Candidate), Candidates),

    % compute the cost+list for all the candidate lists
    maplist(art_cost, Candidates, CostsWithArtLists),

    % sort the list, which will put them in order of cost
    % but lowest-to-highest
    sort(CostsWithArtLists, CostsLowToHigh),

    % flip the list around and deconstruct the highest 
    % as our result
    reverse(CostsLowToHigh, [Cost-ArtList|_]). 

library(aggregate) 可能有更有效的方法,但我想不通。

顺便说一句,我认为您的代码中根本不需要copy_term/2,当我看到看起来像一堆匿名变量的术语时,我总是很怀疑:genera(_,_,_,_)——似乎不太可能我是说你的意思是“任何四件事都适用。”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 2023-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多