読み込みの問題|バックトラック:01選択(最大プルーニング)

目次

1.最適なローディング問題との比較

2.初船の貨物の選び方

3.選択ツリーのバックトラッキングアルゴリズム

4.バックトラッキングアルゴリズムの剪定操作最適化


ローディングの問題:あるN容器が有する2隻の船にロードされる錘C1およびC2容器の重量がiはウィスコンシンとΣwi<= C1 + C2。

これらの2隻の船にこれらのn個のコンテナを積み込むための合理的な積み込み計画があるかどうか尋ねます。もしそうなら、積載計画を見つけてください。

問題分析:実際には、すべての商品を最初の船に積み込み、次に2番目の船に積み込んで解決策を与えることができるかどうかとして理解できます。

考慮すべき主なことは、最初の船をどのようにインストールするかです?この問題が解決されたら、残りを2隻目の船に入れることができます。 


1.最適なローディング問題との比較

最初に、別の同様の問題を見てみましょう。

最適な積み込みの問題:重荷cの  船に積み込まれるコンテナのバッチがありますここで、コンテナー重量はiです最適な積載問題では、積載量の制限なしに、できるだけ多くのコンテナが船に積載されること決定する必要があります。

       明らかに、最適なローディング問題は貪欲に解決できます貪欲な選択:収まらないまで、毎回最小の重量のコンテナを選択してください。 

       ただし、読み込みの問題は上記のように貪欲になることはできません最初の船にできるだけ多くのコンテナーをロードさせ、上記の貪欲な選択戦略を使用すると、最初の船のスペースが無駄になりやすく、結果は最適ではありません。次の反例を見ることができます:


2.初船の貨物の選び方

       上で最初の船は貪欲ではないことが説明されたので、それはスペースの浪費を引き起こし、次善の結果をもたらします!では、どのように最初の船の貨物を選ぶべきでしょうか?

       最初の船に積載される商品の量が多いほど良いというわけではありませんが、最初の船に積載される商品の重量が大きいほど良いです。つまり、最初の船はできるだけ多くの船で満たされ、残りの貨物はすべて2番目の船に引き渡される必要があります

       次に、最初の船の実現プロセスは、実際には  バックパックDP | 01バックパックの問題  です。各貨物には、搭乗または搭乗しないという2つの選択肢しかありません。バックパックのサイズがc1であるという条件下で、値と重量の両方を持つアイテムを選択します。 、容量範囲内で最大値を可能に!

       動的プログラミングに加えて、実際には別の方法があります。それはバックトラッキングアルゴリズムです。以下で詳しく説明してください!


3.選択ツリーのバックトラッキングアルゴリズム

        まず激しい列挙解決策を見てみましょう。n個のアイテムについて、n桁の2進数をすべて列挙し、各桁がマイナーコンテナーに対応しているかどうかを確認します。つまり、すべての列挙メソッドが含まれています。1つずつ列挙しながら、最も船を満たすことができる選択肢を記録してください!この選択での総重量cw記録し、bestwは荷重範囲の最大cwを記録します

  [例としてn = 3とします]列挙の順序を選択できます。

  • 辞書順:000、001、010、011、100、101、110、111
  • サブディクショナリの逆順:ディクショナリの逆順
  • グレイコードシーケンス:000、001、011、010、110、111、101、100(cwの計算量を削減)

       ブルートフォース列挙アルゴリズムの欠点は明白です。それは多くの不要な選択を通過しますが、プルーニングするのは簡単ではありません。 


        バックトラッキングアルゴリズムは、暴力的な列挙を合理的に実現したものと言えます。まず、すべての列挙方式を選択決定ツリーとして描画します(下図に示すように、リーフ部分は全決定です)。各決定はツリーのエッジに対応し、ツリーのノードは選択の結果です。次に、バックトラッキングアルゴリズムの本質は、このツリーを深く検索することです

以下の図に、バックトラッキングアルゴリズムの特定のプロセスを示します。これは、実際には単純なdfs〜です。 

  • 初期化:cw = bestW = 0
  • 呼び出し:backstrack(1)

       ツリー構造が実際にコードに反映されていないことがわかります。しかし、私たちの意思決定の本質はツリーで具現化できるので、コード全体のトラバースはツリーの深い検索です。バックトラッキングアルゴリズムは素晴らしいです!以下は、バックトラッキングプロセス全体を理解するための例です。条件:W [16,15,15]、c = 30。


このバックトラッキングアルゴリズムのコード実装:

int cw;  //当前重量
int bestW;  //最优重量
int c;   //船的最大承载量
int n;  //货物的数量
int w[100];   //对应 n 个集装箱的重量

/* 尽量装满第一艘船的回溯算法
 * step:层数 */
void backtrack(int step) {
    /* 到达了树叶 */
    if(step > n) {
        if(bestW < cw && cw <= c)
            bestW = cw;
        return;
    }

    cw += w[step];
    backtrack(step + 1);
    cw -= w[step];

    backtrack(step + 1);
}

4.バックトラッキングアルゴリズムの剪定操作最適化

        上記のバックトラッキングアルゴリズムは枝刈りされていません。実際、全体的な複雑さとブルートフォースの列挙の間に違いはありません。次に、プルーニングアルゴリズムをバックトラッキングアルゴリズム用に最適化します。


プルーニング操作1:最終的な制約を満たさないサブツリーの場合、走査をスキップします。【制限事項】


剪定操作2:最適解を見つけられないサブツリーの場合、走査をスキップします。【限定条件】

(以下の疑似コードは、特定の選択肢を記録するためにx配列も追加し、最適値を更新しながら最適解を維持します)

通常、境界条件は自分で作成する必要があります。たとえば、rを導入して記録します。


剪定操作3:事前に最適値を更新してください。

       葉ノードの最適値を更新するだけでなく、他のすべてのノードで更新して、葉ノードに直接戻る必要がなくなりました。このようにして、境界条件の剪定範囲を広くすることができます。


剪定操作を伴うバックトラッキングアルゴリズムのコード実装:

        コーディング...

おすすめ

転載: blog.csdn.net/weixin_43787043/article/details/105815795