certian条件を満たす集合のサブセットを生成するためのアルゴリズム
質問
、私は要素のソートされたリストを与えていると私はいくつかの条件を満たしたすべてのサブセットを生成するとします要素がそれを満たしてくださいます。
(100,29)(0,1,40)、(0)、等... 例えば、100未満のすべての正の整数のリストを与えられ、その和130よりも小さいサブセットを決定します>どのように私は(好ましくはPythonで)ことを行うことができますか?
ありがとう! :)
解決
あなたは分枝限定の技術を使用して、すべてのサブセットを生成することができますすることができます「ルートが制約をsatifyていない場合は、ツリーのこのブランチを探求しない」プルーン条件として使用して、(既に決定サブセットのスーパーセットを生成する)インクリメンタル方式で全てのサブセットを生成します。
あなたが制約に関する一般的なようにしたい場合は、私はこれが最善の戦略だと思います。
ことができます、時間のかかる検索をマッピングし、メモリのオーバーヘッドを導入することによるものであることができ、メモ化を避けるために:そうでなければ、多くの時間と同じサブセットを生成し、正しい方法でサブセットを生成するコードを記述するようにしてくださいそのようにしてサブセットを生成する
GetAllSubsets(List objects) {
List generated = {};
GetAllSubsets(generated, [], objects);
return generated;
}
GetAllSubsets(List subsetGenerated, List objectFixed, List objectsToFix) {
GetAllSubsets(subsetGenerated, objectFixed, objectsToFix.sublist(1, objectsToFix.length());
if (satisfy(toCheck = objectsFixed.add(objectsToFix.get(0)))) {
subsetGenerated.add(toCheck);
GetAllSubsets(subsetGenerated, toCheck, objectsToFix.sublist(1, objectsToFix.length());
}
}
実際には、GetAllSubsetsの最初の呼び出しによって追加されたサブセットは、サブセットが第2の呼(剪定条件に違反していない場合)、その要素を持っているので、交差点によって追加objectsToFixの最初の要素を有していませんサブセット2組の空で生成された。
他のヒント
あなたは空のセットで始まり、多くの要素を追加しようとすると、(したがって、そのスーパーセットのすべて)のサブセットのいずれかが条件を満たさない場合は、実行の再帰的なラインであきらめて、再帰的に自分のセットを構築することができます。ここでは条件適合サブセットを一覧表示したい集合Sを想定し、いくつかの擬似コードは、です。便宜上、Sの要素はXとしてインデックス付けすることができると仮定する(0)、X(1)、X(2)、...
EnumerateQualifyingSets(Set T)
{
foreach (x in S with an index larger than the index of any element in T)
{
U = T union {x}
if (U satisfies condition)
{
print U
EnumerateQualifyingSets(U)
}
}
}
の最初の呼び出しが空集合としてTとなるであろう。次に、条件に合致Sのすべてのサブセットが印刷されることになります。この戦略は、条件を満たしていないSのサブセットはありません1つに含まれないという事実に決定的に依存しています。
これを行う方法は確かにありますが、あなたは何とか条件を制約することができない限り、O(2 ^ n)の措置をとるだろう。あなたが考える場合は、例えば、すべてのサブセットが選択される1-100の条件(例えば、<はEMは>私は/全角> <<<全角>私は1- /全角> <ΣのN )、そして、あなたはすべてのサブセットを列挙することになります。
は、
を見ていると思いますfor i in the powerset of {1-n}
if cond(i)
note that set
あなたは、単にsの0から全てのバイナリ番号を生成することによって、設定の冪を得ることができます。のN の-1、およびサブセットのための私の選択要素ビットiは1である。
私は、クラススケジュール生成アルゴリズムの似た何かをやりました。私たちのスケジュールクラスには2つの要素を持っていた - 。スケジュールに追加コースのリスト、および追加できるコースのリストを
擬似コード:
queue.add(new schedule(null, available_courses))
while( queue is not empty )
sched = queue.next()
foreach class in sched.available_courses
temp_sched = sched.copy()
temp_sched.add(class)
if(temp_sched.is_valid())
results.add(temp_sched)
queue.add(temp_sched)
アイデアは、(有効な意味は、ユーザによって与えられた要件に適合し、時間の競合などを持っていない)空のスケジュールと利用可能なクラスのリストを開始するには、有効なスケジュールのために木を下に検索することです。スケジュールが無効である場合、それは捨てている - 我々は(すなわち、木を剪定)のクラスを追加することにより、有効、無効なスケジュールを作成することはできません。
。それはあなたの問題で動作するようにこれを修正するのは簡単である必要があります。
ここでサブセットを生成するために、再帰関数を使用して、akappaの答えの具体的な例です。
def restofsubsets(goodsubset, remainingels, condition):
answers = []
for j in range(len(remainingels)):
nextsubset = goodsubset + remainingels[j:j+1]
if condition(nextsubset):
answers.append(nextsubset)
answers += restofsubsets(nextsubset, remainingels[j+1:], condition)
return answers
#runs slowly
easieranswer = restofsubsets([], range(101), lambda l:sum(l)<40)
#runs much faster due to eliminating big numbers first
fasteranswer = restofsubsets([], range(100,-1,-1), lambda l:sum(l)<40)
#runs extremely slow even with big-numbers-first strategy
finalanswer = restofsubsets([], range(100,-1,-1), lambda l:sum(l)<130)
私は最悪の場合、あなたはまだすべてのサブセットを生成し、それが修飾するかしないかどうかを判断するために、各セットの合計を計算する必要があると思います。漸近的に、それは手続きを生成する部分集合のコストです。
以下は、私は同じ考えのためにJavaScriptで実装される方法です。
//this is to generate an array to test
var numbers = (function(start, end){
var result = [],
i = start;
for(; i <= end; i++){
result.push(i);
}
return result;
})(1, 12);
//this is the qualifying function to determine if the generated array is qualified
var fn = (function(maxSum){
return function(set){
var sum = 0;
for(var i = 0 ; i< set.length; i++){
sum += set[i];
if( sum > maxSum ){
return false;
}
}
return true;
}
})(30);
//main function
(function(input, qualifyingFn){
var result, mask, total = Math.pow(2, input.length);
for(mask = 0; mask < total; mask++){
result = [];
sum = 0;
i = input.length - 1;
do{
if( (mask & (1 << i)) !== 0){
result.push(input[i]);
sum += input[i];
if( sum > 30 ){
break;
}
}
}while(i--);
if( qualifyingFn(result) ){
console.log(JSON.stringify(result));
}
}
})(numbers, fn);