How to correctly filter a clause that returns mult

2019-07-10 01:03发布

问题:

I'm trying to correctly filter the values returned from a clause (it is returning multiple duplicated values). I'm having a hard time understanding the logic programming, sorry if its an stupid question.

These are my facts/predicates:

home(peter, sanFrancisco, 1000).
home(ash, sanFrancisco, 100).
home(juan, sanFrancisco, 400).
home(juan, california, 700).
home(ash, california, 600).
home(peter, california, 500).
home(peter, vegas, 100).
home(ash, vegas, 80).
home(juan, vegas, 60).

What im trying to do is to retrieve the name; the condition is that I have to retrieve only the ones that from a certain city their home is the most expensive from there but also if the second most expensive home from that same city is less than half the price of the first. I cannot use lists.

The most expensive from each city:

home(peter, sanFrancisco, 1000).
home(juan, california, 700).
home(peter, vegas, 100).

Second most expensive from each city:

home(juan, sanFrancisco, 400).
home(ash, california, 600).
home(ash, vegas, 80).

What I expect as a result:

peter.

What I have tried so far but with no success..

%Return the most expensive from each city.
theMostExpensive(Name, City):-
    home(Name, City, Price),
    fromEach(City, Price).

fromEach(City, Price):-
    forall(home(_, City, Price2), Price>= Price2).

%Return the second most expensive from each city. Not sure if working correctly.
secondMostExpensive(Name, City):-
    owner(home),
    not(theMostExpensive(Name, City)),
    theMostExpensive(Name2, City),
    Name \= Name2.

%Return a lot of duplicated values and wrong..
superExpensive(Name):-
    theMostExpensive(Name, City),
    secondMostExpensive(Name2, City),
    Name \= Name2,
    City \= City2,
    home(Name, City, Price),
    home(Name2, City2, Price2),
    Price > Price2 + (Price / 2).

I think somewhere in superExpensive is doing something like everyone * everyone?

回答1:

The most expensive home in a town is such that no other home in that town is more expensive than it:

most_expensive( home( Name, Town, Price)):-
  home( Name, Town, Price),
  \+ (home( _, Town, P), P > Price).

This gets us

5 ?- most_expensive( H ).
H = home(peter, sanFrancisco, 1000) ;
H = home(juan, california, 700) ;
H = home(peter, vegas, 100) ;
false.

The second most expensive home in a town is such that is the most expensive among the homes which are not the most expensive home in that town:

second_most_expensive( home( Name, Town, Price)):-
  most_expensive( home( _, Town, TopPrice) ),
  home( Name, Town, Price), Price < TopPrice,
  \+ (home( _, Town, P), P < TopPrice, P > Price).

And this gets us

8 ?- second_most_expensive( H ).
H = home(juan, sanFrancisco, 400) ;
H = home(ash, california, 600) ;
H = home(ash, vegas, 80) ;
false.

So then, with

top_house_owner( Name ) :-
  most_expensive( home( Name, T, P) ),
  second_most_expensive( home( _, T, P2 ) ),
  P2 < P div 2.

we get

12 ?- top_house_owner( N ).
N = peter ;
false.


回答2:

You can find a simple solution if you think of the problem in the following way.

A person X meets your conditions if and only if X has a house in some city Y, and there is no one else in Y with a house costing at least half of the price of X's.

% true if Name2's home is at least half of the price of Name1's
aboveHalf( City, Name1, Name2 ) :-
  home( Name1, City, P1 ),
  home( Name2, City, P2 ),
  Name1 \= Name2,
  P2 > P1 div 2.

superExpensive( Name ) :-
  home( Name, City, _ ),
  \+ aboveHalf( City, Name, _ ).


标签: prolog