首页 文章

如何在Prolog中找到第k代家谱?

提问于
浏览
1

我试图找到一个特定家庭的所有家庭成员的列表.2461860_代 . 我们也得到了家庭的第一批成员和家谱 . 下面是我的KB相同和实现 . 我无法想象如何为这个家谱树获得 kth 代?让我们说 k = 4 . 一种方法是我可以找到这样的关系的4倍:

4thGen(X,Y) :- parent(X,A),parent(A,B),parent(B,C),parent(C,Y)

但我认为这不是正确的方法 .

male(alex).
male(romeo).
male(oscar).
male(peter).
male(bruno).
male(georg).
male(otto).
male(pascal).
male(jean).

female(lina).
female(julia).
female(rosa).
female(eva).
female(ruth).
female(silvia).
female(ida).
female(irma).
female(olga).
female(marie).
female(tina).

parent(alex,julia).
parent(alex,rosa).
parent(lina,julia).
parent(lina,rosa).
parent(romeo,peter).
parent(julia,peter).
parent(rosa,silvia).
parent(oscar,ida).
parent(eva,ida).
parent(eva,bruno).
parent(peter,bruno).
parent(peter,georg).
parent(peter,irma).
parent(ruth,georg).
parent(ruth,irma).
parent(silvia,otto).
parent(silvia,pascal).
parent(irma,olga).
parent(irma,jean).
parent(otto,olga).
parent(otto,jean).
parent(jean,tina).
parent(marie,tina).






father(X,Y):-parent(X,Y),male(X).
grandfather(X,Y):-father(X,Z),parent(Z,Y).

1 回答

  • 2

    为了生成更一般的谓词,您可以使用递归:

    kthGen(X,Y,1):-parent(X,Y).
    kthGen(X,Y,K) :- parent(X,A),K1 is K-1,kthGen(A,Y,K1).
    

    以下是一些查询:

    ?- kthGen(alex,julia,1).
    true ;
    false.
    
    ?- kthGen(alex,peter,2).
    true ;
    false.
    
    ?- kthGen(alex,bruno,2).
    false.
    
    ?- kthGen(alex,bruno,3).
    true ;
    false.
    

    这里要注意两个重要的事情:

    • 首先你的图表是 directed (例如,如果 parent(A,B) 你不能 parent(B,A) ),这很重要,因为如果它是 undirected 你可能会陷入循环(例如 kthGen(alex,julia,4). 会因为路径 alex->julia->alex->julia 而成功,你可以通过添加另一个列表来解决这个问题跟踪你去过的人 .

    • 其次,如果你尝试:

    ?- kthGen(alex,bruno,K). ERROR: Arguments are not sufficiently instantiated ERROR: In: ERROR: [8] kthGen(alex,bruno,_7630) ERROR: [7] <user>

    所以谓词 kthGen/3 没有关系行为 . 您可以使用库CLPFD:

    :- use_module(library(clpfd)).
    
    kthGen(X,Y,1):-parent(X,Y).
    kthGen(X,Y,K) :- parent(X,A),K1 #= K-1,kthGen(A,Y,K1).
    

    现在,如果你尝试:

    ?- kthGen(alex,bruno,K).
    K = 3 ;
    false
    

    好多了 !! .


    UPDATE

    为了从人X中找到第k代人,你可以相应地修改:

    :- use_module(library(clpfd)).
    
    kthGen(Y,1,[Y]).
    kthGen(X,K,[X|T]) :- parent(X,A),K1 #= K-1,kthGen(A,K1,T).
    

    例:

    ?- kthGen(alex,4,L).
    L = [alex, julia, peter, bruno] ;
    L = [alex, julia, peter, georg] ;
    L = [alex, julia, peter, irma] ;
    L = [alex, rosa, silvia, otto] ;
    L = [alex, rosa, silvia, pascal] ;
    false.
    

    这给了亚历克斯所有可能的第四代 . 如果你想从alex或lina中找到更复杂的例如第4代,你可以单独找到它,写一个连接结果的另一个谓词...


    UPDATE 2

    在上次更新中,我跟踪所有人,直到第4代 . 如果你想要第4代只需修改如下:

    kthGen(Y,1,[Y]).
    kthGen(X,K,L) :- parent(X,A),K1 #= K-1,kthGen(A,K1,L).
    

    Examlpe:

    ?- kthGen(alex,4,L).
    L = [bruno] ;
    L = [georg] ;
    L = [irma] ;
    L = [otto] ;
    L = [pascal] ;
    false.
    

    现在,如果您想将所有结果放在一个列表中:

    ?- findall(X,kthGen(alex,4,[X]),L).
    L = [bruno, georg, irma, otto, pascal].
    

相关问题