Проверка Prolog, содержит ли список в 2 раза больше элементов другого списка

#prolog

#prolog

Вопрос:

Итак, задача не такая сложная, но проблема в том, что я не могу использовать для этого сравнения терминов или чисел или сортировку. Я также сделал проверку, подтверждающую, что 2 списка содержат одни и те же элементы (так что эту часть можно игнорировать), но я не знаю, как выполнить проверку конкретно для вопроса. Например, если у меня есть это: List1 [1,2] и List2 [1,2,1,2] , это должно быть true, если List2 равно [1,2,2] или [1,2,1,2,1] должно быть false.

Комментарии:

1. Почему бы просто не взять меньший список, дублировать его в новый список с каждым элементом дважды, затем сгенерировать перестановки этого списка, и если один из них совпадает с другим списком, это верно?

2. Используйте рекурсию, если вы нашли первый элемент, затем выполните элемент в оставшемся списке.

Ответ №1:

Вот базовый подход, который не использует никаких чисел. Он использует dif/2 (альтернативно, use = ), что является «сравнением терминов», но не тем, который вы, возможно, имели в виду.

Во-первых, предикат для выражения того, что элемент встречается в списке ровно 0 раз (другими словами, он не является членом списка):

 exactly0_list(_X, []).
exactly0_list(X, [Y | Ys]) :-
    dif(X, Y),
    exactly0_list(X, Ys).
 

Например:

 ?- exactly0_list(x, [a, b, c]).
true ;
false.
 

Но:

 ?- exactly0_list(b, [a, b, c]).
false.
 

Основываясь на этом, предикат для выражения того, что элемент встречается в списке ровно 1 раз:

 exactly1_list(X, [X | Ys]) :-
    exactly0_list(X, Ys).
exactly1_list(X, [Y | Ys]) :-
    dif(X, Y),
    exactly1_list(X, Ys).
 

Посмотрите, как это похоже. Это ведет себя следующим образом:

 ?- exactly1_list(b, [a, b, c]).
true ;
false.

?- exactly1_list(b, [a, b, c, b]).
false.
 

Если вы видите, что появляется шаблон, реализуйте предикат exactly2_list/2 в тех же строках. Он должен вести себя так:

 ?- exactly2_list(b, [a, b, c, b]).
true ;
false.

?- exactly2_list(b, [a, b, c, b, b]).
false.
 

Затем используйте это, чтобы сравнить каждый элемент вашего первого списка со вторым списком.

Комментарии:

1. Но это не используется, например, для [1,1] и [1,1,1,1] , но должно

Ответ №2:

Я сделал свой подход следующим образом: «List1 [1,2] и List2 [1,2,1,2] должно быть true, если List2 равно [1,2,2] или [1,2,1,2,1] должно быть false».

1. Предикат check2times сравнивает 2 списка, затем вызывает проверку предиката. задача проверки — сравнить и дать общее количество пар, встречающихся в списке, в виде списка [1,1]. Затем используйте предикат sum для суммирования списка (например, [1,1] = 2 ). Затем просто проверьте, должна ли сумма = 2 возвращать true, иначе это будет false.

 check2times([H|T],[H2|T2]):-
    check([H|T],[H2|T2],N),
    sum(N,S),
    S=2. 
 

2. проверьте предикат

 check(_,[],[]).
check([A,B|T],[H1,H2|L],[N|R]):-
    [A,B]=[H1,H2],
    N is 1 0,
    check([A,B|T],L,R).
check([A,B|T],[H1,H2|L],N):-
     [A,B]=[H1,H2],
    check([A,B|T],L,N).
 

3. предикат суммы

 sum([],0).
sum([H|T],S):-
    sum(T,S1),
    S is S1 H.
 

Собрать все это вместе:

 check2times([H|T],[H2|T2]):-
    check([H|T],[H2|T2],N),
    sum(N,S),
    S=2.    
check(_,[],[]).
check([A,B|T],[H1,H2|L],[N|R]):-
    [A,B]=[H1,H2],
    N is 1 0,
    check([A,B|T],L,R).
check([A,B|T],[H1,H2|L],N):-
     [A,B]=[H1,H2],
    check([A,B|T],L,N).

sum([],0).
sum([H|T],S):-
    sum(T,S1),
    S is S1 H.
 

Примеры:

 ?-check2times([1,2],[1,2,1,2]).
true
false
check2times([1,2],[1,2,1]).
false
?-check2times([2,2],[2,2,2,2]).
true
false
?-check2times([2,2],[2,2,2,2,2,2]).
false
?-check2times([2,2],[2,4,3,5,2,2,3,6,5,3,2,2]).
true
false
?-check2times([b,b],[b,b,a,d,f,g,w,q,b,b,h,y]).
true
false
?-check2times([b,b],[b,b,5,6,f,g,1,2,b,b,h,y]).
true
false
?-check2times([1,2,3,4],[1,2,3,4,1,2,3,4,1,2,3,4]).
false
?-check2times([1,2,3,4],[1,2,3,4,1,2,3,4]).
true
false