Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NP-complete knapsack

I saw this ECLiPSe solution to the problem mentioned in this XKCD comic. I tried to convert this to pure Prolog.

go:-
    Total = 1505,
    Prices = [215, 275, 335, 355, 420, 580],
    length(Prices, N),
    length(Amounts, N),
    totalCost(Prices, Amounts, 0, Total),
    writeln(Total).

totalCost([], [], TotalSoFar, TotalSoFar).
totalCost([P|Prices], [A|Amounts], TotalSoFar, EndTotal):-
    between(0, 10, A),
    Cost is P*A,
    TotalSoFar1 is TotalSoFar + Cost,
    totalCost(Prices, Amounts, TotalSoFar1, EndTotal).

I don't think that this is the best / most declarative solution that one can come up with. Does anyone have any suggestions for improvement? Thanks in advance!

like image 733
Ashley Avatar asked Jun 06 '11 14:06

Ashley


People also ask

Is knapsack NP-complete?

Theorem 1 Knapsack is NP-complete. Proof: First of all, Knapsack is NP. The proof is the set S of items that are chosen and the verification process is to compute ∑i∈S si and ∑i∈S vi, which takes polynomial time in the size of input.

Why is knapsack NP-hard?

The knapsack problem, though NP-Hard, is one of a collection of algorithms that can still be approximated to any specified degree. This means that the problem has a polynomial time approximation scheme. To be exact, the knapsack problem has a fully polynomial time approximation scheme (FPTAS).

Is subset sum & knapsack problem NP-complete?

This algorithm is polynomial in the values of A and B, which are exponential in their numbers of bits. However, Subset Sum encoded in unary is in P, since then the size of the encoding is linear in B-A. Hence, Subset Sum is only weakly NP-Complete.

Why 0 1 knapsack is not completely solved yet?

0-1 Knapsack cannot be solved by Greedy approach. Greedy approach does not ensure an optimal solution. In many instances, Greedy approach may give an optimal solution.


1 Answers

Since you mention SWI-Prolog why not

?- use_module(library(clpfd)).

and library(lambda)

?- Total = 1505, Prices = [215, 275, 335, 355, 420, 580],
   maplist(\P^A^M^(P*A #= M, A #>=0),Prices,Amounts,Ms), sum(Ms, #=, Total).

By stating this, all variables in the list Amounts are in a finite range. So there is no need to "do the math" for an upper bound (which often goes wrong anyway). To see concrete solutions, labeling/2 is needed:

?- Total = 1505, Prices = [215, 275, 335, 355, 420, 580],
   maplist(\P^A^M^(P*A #= M, A #>=0),Prices,Amounts,Ms), sum(Ms, #=, Total),
   labeling([], Amounts).
    Total = 1505,
    Prices = [215,275,335,355,420,580],
    Amounts = [1,0,0,2,0,1],
    Ms = [215,0,0,710,0,580] ;
    Total = 1505,
    Prices = [215,275,335,355,420,580],
    Amounts = [7,0,0,0,0,0],
    Ms = [1505,0,0,0,0,0].
like image 58
false Avatar answered Jan 01 '23 19:01

false