How can I speed up this program? It is a coin hold

2019-08-03 16:08发布

问题:

So this is a program where it calculates the fewest number of coins to carry with certain values on these coins. The program works, but it's way too slow... When you replace the length of the values 7 or less, it works... But 8 or above, it's really, really slow. Is there any way to speed up this program?

% LIBRARIES NEEDED FOR FUNCTION TO WORK
:- lib(ic).
:- lib(ic_global).
:- lib(branch_and_bound).

questionSix(Values, Coins) :-
    init_vars(Values, Coins),
    coin_cons(Values, Coins, Pockets),
    clever_cons(Values, Coins),
    Min #= sum(Coins),
    minimize((labeling(Values), labeling(Coins), check(Pockets)), Min).

init_vars(Values, Coins) :-
    length(Values, 8),
    occurrences(5, Values, 1),
    Values :: 1..99,
    increasing(Values),
    length(Coins, 8),
    Coins :: 0..99.

increasing(List) :-
    ( fromto(List, [This, Next | Rest], [Next | Rest], [_])
    do
        This #< Next
    ).

clever_cons(Values, Coins) :-
    ( fromto(Values, [V1 | NV], NV, []), 
      fromto(Coins, [N1 | NN], NN, [])
     do
        ( NV = [V2 | _]
            -> N1*V1 #< V2;
            N1*V1 #< 100
        )
    ).

coin_cons(Values, Coins, Pockets) :-
    ( for(Price, 1, 99),
    foreach(CoinsforPrice, Pockets),
    param(Coins, Values)
    do
        price_cons(Price, Coins, Values, CoinsforPrice)
    ).

price_cons(Price, Coins, Values, CoinsforPrice) :-
    ( foreach(V, Values), foreach(C, CoinsforPrice), foreach(Coin, Coins),
    foreach(Prod, ProdList)
    do
        Prod = V*C,
        0 #=< C,
        C #=< Coin
    ),
    Price #= sum(ProdList).

check(Pockets) :-
    ( foreach(CoinsforPrice, Pockets)
    do
        once(labeling(CoinsforPrice))
    ).

Any help is appreciated! Thanks!

回答1:

First observation: if you put labeling(Coins) before labeling(Values), the time improves dramatically. Roughly speaking, that's because in this problem number of coins is much more important than values of coins.

Second observation: you can't get less than 7 coins no matter how many values you allow. That's because if you run your program with 7 values, you can see that every coin is used once in the optimal solution. So if you have more than 7 values, only 7 of them will be used, or the number of coins will be more than 7 and the solution will be not optimal.

With these observations in mind, you can just change

minimize((labeling(Values), labeling(Coins), check(Pockets)), Min).

to

bb_min((labeling(Coins), labeling(Values), check(Pockets)), Min, bb_options{from:7}).