2012-01-08 15 views
3

私はPrologを初めて使用しています。これは先週の金曜日に起きた現実世界の問題で、これはCS宿題ではないと私に信じています。名刺印刷 - 一種のナップザックタスク

名刺を印刷したい場合は、900枚(1枚あたり9枚のカードで100枚)のブロック単位で印刷することができます。誰のためのカードもいくつかのブロックに分散してはいけません。人々はEG、カードの異なる量を命じ:

% "braucht" is german and means "needs" 
braucht(anton,400). 
braucht(berta,200). 
braucht(claudia,400). 
braucht(dorothee,100). 
braucht(edgar,200). 
braucht(frank,400). 
braucht(georg,100). 

私は900枚の名刺の適切なブロックを見つけるために、次の定義をまとめ:

block(0,[]). 
block(N,[H|T]) :- 
    braucht(H,Nh), 
% \+(member(H,T)), 
    D is N - Nh, 
    D >= 0, 
    block(D,T). 

これは、カードの人々のブロックの素敵なリストを作成します900枚のカードブロックに一緒にフィットする。しかし、私はコメント行 "+ + member ...."を有効にして、私に "false"を与えても動作しなくなります。しかし、私は誰もそのブロックに何度も出くわしていないことを保証する必要があります。私はここで間違って何をしていますか?

答えて

3

達成したいのは、Hがリストの末尾Tに表示されないという制約を設定することです。ただしを呼び出すとはまだバインドされていないので、member(H, T)が成功し、したがって\+ member(H,T)が失敗します。

制約プログラミングを使用せず、代わりに純粋なPrologを使用する場合は、別の方向のチェックを使用して、Hが既にそのポイントまで集約された人のリストに存在するかどうかを確認する必要があります。何かのように:

block(0, List, List). 
block(N, Rest, List) :- 
    braucht(H, Nh), 
    \+(memberchk(H, Rest)), % will fail when H is already in Rest 
    D is N-Nh, 
    D >= 0, 
    block(D, [H|Rest], List). 

述語block/3は述語block/2から呼び出すことができます:あなたのブロックの述語で2番目の引数が「出力」の場合

block(N, List) :- 
    block(N, [], List). 
+0

は、私は私のアプローチはかなりナイーブだった、もう1つは、アカウントにプロローグが定義を処理する方法を取るために持っていることがわかります。しかし、今私は先に進むことができます。どうもありがとう! – Patrick

+0

制約プログラミングソリューションはどのように見えるのですか – Sebastian

+0

いくつかの可能性があります。 CPシステムによっては、グローバルナップザックまたはビンの梱包の制約がある場合があります。また、累積スケジューリング制約を使用して、ナップザック問題をモデル化することもできます。 "単純な"制約しかない場合は、リストの可能な要素ごとに1つの変数Bをドメイン[0,1]で設定することができます。すべての要素のB *値の積を合計し、合計を最大容量に制限します。ブール変数にラベルを付けます。 – twinterer

2

、その後、あなたの問題はTであるということですメンバー(_、T)は常に成功します。例えば:

?- member(anton,T). 

T = [anton|_] 
T = [_,anton|_] 
T = [_,_,anton|_] 

のように...

+0

私は今理解しています。 [H | T]は左から右に処理され、Prologはバインドしない限りTが望むものを処理するため、Tは解放されます。ありがとう! – Patrick

関連する問題