web-dev-qa-db-ja.com

距離に関係しないコストを最小限に抑えながら、数直線上の訪問ポイント

このACM ICPCの問題についてサポートが必要です。私の現在の考えは、これを最短経路問題としてモデル化することです。これは、問題ステートメントで説明されています。

問題

N = 1000を除く-500,000 to 500,000からdistinct位置の1次元の数直線に沿って配置されたx=0核廃棄物コンテナがあります。人はすべてのゴミ箱を集めることを任されています。廃棄物コンテナが収集されない毎秒、それは1ユニットの放射線を放出します。人はx = 0から開始し、毎秒1ユニットを移動できます。廃棄物の収集にかかる時間はごくわずかです。すべてのコンテナを収集する際に放出される放射線の最小量を見つけたいと考えています。

サンプル入力:

4[-12, -2, 3, 7]にあるコンテナ。

これらのコンテナーを収集するための最適な順序は[-2, 3, 7, -12]で、最小の50ユニットを放出します。説明:人は2秒で-2に行き、その間に2 unitsの放射線が放出されます。次に、彼は3(距離:5)に行き、バレルが2 + 5 = 7単位の放射線を放出するようにします。そのバレルが4ユニットを放出したx = 7に到達するには、彼は2 + 5 + 4 = 11秒以上かかります。そのバレルが19ユニットを放出したx = -12に到達するには、彼は2 + 5 + 4 + 19 = 30秒かかります。 2 + 7 + 11 + 30 = 50、それが答えです。

メモ

明白なO(N!)ソリューションがあります。しかし、私は最も近いものに移動する、または最も近いクラスターに移動するなどの貪欲な方法を調査しましたが、それらはうまくいきませんでした。

私はこの問題についてかなり長い間考えてきましたが、グラフ検索の問題としてモデル化しました:

  1. 0をベースライン位置として挿入します(これが初期状態になります)
  2. 次に、位置を最小から最大に並べ替えます。
  3. 次に、BFS/PFSを実行します。ここで、stateは、で構成されています。
    • 2つの整数lrは、すでにアクセスしたソート済み位置配列の連続範囲を表します
    • 範囲の左端か右端かを示す整数loc
    • 経過時間を示す整数time
    • これまでの総コストを示す整数の「コスト」(これまでにアクセスしたノードに基づく)
  4. 各状態から[l-1、r]および[l、r + 1]に移動し、他の3つの整数を適宜調整します。
  5. 最終状態は[0、N]で、両方の終了位置をチェックしています。

ただし、[L, R, loc]は状態を一意に定義していないようで、costをそれぞれ最小化しながらL, R, loc, and timeを格納する必要があります。これは指数関数アルゴリズムにつながりますが、それはまだどんなに良いものにも遅すぎます。

誰かが私のアイデアを拡張したり、正しい方向に押し込んだりするのを手伝ってくれる?

編集:多分これは、動的プログラミング最適化問題としてモデル化できるでしょうか?考えてみると、グラフ検索ソリューションと同じ問題があります。現在のcostが低いからといって、それがそのサブ問題の最適な答えであるとは限りません。timeも答えに大きく影響します。

貪欲は機能しません:特定の場所に移動するコストを推定する貪欲な選択アルゴリズムがあります(たとえば、右に移動すると、左の樽までの距離が2倍になります)。

優先順位優先の検索をヒューリスティックで実行できますか?ヒューリスティックは、現在のトリップのコストと経過時間を組み合わせることができます。

18
Barron W.

問題を位置のペアの有向グラフとして見ることで、これを改善できると思います。

この例では、値-9、-6、-1、3、および5の行を使用します。

テキストだけでグラフを描くのは難しいので、ペアを表として表現します。セルは、これら2つの位置の間のすべてのコンテナーが収集された状態を表していると考えることができます。各セルには2つの値があり、1つは左に移動するコストを表し、もう1つは右に移動する(次のコンテナーに移動する)コストを表します。

値は、2つのポイント間の距離にこれらの2つのポイントの外側にあるバレルの数+ 1を乗算して簡単に計算できます。両方の数が同じ符号を持つセルは、反対符号のすべてのバレルが収集された場合を表します。これらは、ゼロから離れる方向のバレルの数のみを使用して計算されます。

表のXの値は、その方向に進むことができないことを意味します(その方向のバレルはすべて取得されています)。行はコレクターの現在の位置を表し、列は次の反対のバレルの位置を表します。

    +------+------+------+------+------+
    |  -9  |  -6  |  -1  |   3  |   5  |
+---+------+------+------+------+------+
|-9 |      |      |      | X, 24| X, 14|
+---+------+------+------+------+------+
|-6 | 3, X |      |      | 9, 27| 6, 22|
+---+------+------+------+------+------+
|-1 |      |10, X |      |20, 8 |15, 18|
+---+------+------+------+------+------+
| 3 |24, 4 |27, 6 |16, 8 |      | X, 2 |
+---+------+------+------+------+------+
| 5 |14, X |22, X |18, X |      |      |
+---+------+------+------+------+------+

正方形間を移動するためのルールは、やや混乱する可能性があります。

負の数の列の場合、ルールは次のとおりです。

  • 右に移動すると、1つ下のセルに移動します。
  • 左に移動すると、1つのセルが下に移動し、次に対角線上でミラーリングします。
  • 右の値がXの場合、左に移動すると対角線(列と行が等しい)まで移動し、左に1つ移動します。

正の数の列の場合、ルールは次のとおりです。

  • 左に移動すると、1つ上のセルに移動します。
  • 右に移動すると、1つのセルが上に移動し、対角線上でミラーリングします。
  • 左の値がXの場合、右に移動すると対角線に下がり、右に1つ移動します。

これで、ダイクストラのアルゴリズムを実行して、これらの移動ルールを使用してグラフをトラバースし、最適なパスを計算できます。開始位置は(-1、3)と(3、-1)で、初期コストはそれぞれ5と15です。 2つの終了位置((-9、-9)の左側と(5、5)の右側)の値を計算したら、2つのうち小さい方が答えになります。

各ステップの実行時間は次のとおりです。

  • ラインに沿って入力値を最初にソートするためのO(N log N)
  • テーブル/グラフを計算するためのO(N ^ 2)
  • グラフでダイクストラを実行する場合のO(N ^ 2 log N)(注:特定の頂点には最大2つのエッジがあります)。

最初の2つのステップが最後のステップに支配されているため、全体的なランタイムはO(N ^ 2 log N)であり、チャレンジに十分なランタイムです。

4
Cameron

最短距離

私は昨日問題を解決するためにJavaアプリケーションを書きました。SRJがコメントで言ったように、問題は基本的に最短距離の問題です。放射は、最短の値とともに値を累積できることを示しています距離。

基本的に、これが私がしたことです。

  • コンテナ番号をリストに入れます<整数>
  • リストには要素が含まれていますが、
    • 最も近い要素を検索します
    • 要素が1つある場合は、そこを歩いて要素を削除します。
    • 2つの要素がある場合は、パスをコピーして両方の要素に移動します
  • 最小の放射値を持つパスを見つけます。

アプリケーションからの出力は次のとおりです

10 containers are located at [-90, -75, -47, -9, 9, 26, 48, 50, 64, 79].

You walk to position -9 and pick up the container.  The total radiation emitted is 90 units.
You walk to position 9 and pick up the container.  The total radiation emitted is 252 units.
You walk to position 26 and pick up the container.  The total radiation emitted is 388 units.
You walk to position 48 and pick up the container.  The total radiation emitted is 542 units.
You walk to position 50 and pick up the container.  The total radiation emitted is 554 units.
You walk to position 64 and pick up the container.  The total radiation emitted is 624 units.
You walk to position 79 and pick up the container.  The total radiation emitted is 684 units.
You walk to position -47 and pick up the container.  The total radiation emitted is 1,062 units.
You walk to position -75 and pick up the container.  The total radiation emitted is 1,118 units.
You walk to position -90 and pick up the container.  The total radiation emitted is 1,133 units.

アルゴリズムを最適化しなかった。数値の入力リストが並べ替えられていることに気づきませんでした。 (私はドゥーフスです。)

最大値、1,000コンテナー、-500,000から500,000の範囲でコードを実行すると、コードの実行に3秒かかりました。そのほとんどの時間は、コンソールに1,000行の印刷行を書き込んでいました。

私は大きなOの人ではありませんが、最短経路アルゴリズムを歩く私の力はO(Nの2乗)であり、O(N!)ではないと思います。

入力番号が並べ替えられているという事実を利用して、現在位置している場所の両側の2つの番号のみを確認すれば、アプリケーションをO(N)の近くに配置できます。 2つの数値を確認するだけでよいのは、要素を取得したらリストから要素を削除するためです。

貪欲アルゴリズムなどのさまざまなアルゴリズムを使用して、近似解を見つけました。

私のプログラムの実行に3秒ではなく3時間かかっていた場合は、選択する必要があります。

十分なソリューションで十分ですか?

言い換えれば、十分な回答を得るために処理速度を犠牲にしてもかまいませんか?

十分に良い答えで十分であれば、近似アルゴリズムを使用します。

完璧な答えが必要な場合は、すべての最短経路を歩く必要があります。近道はありません。

誰かが私のコードを投稿してほしいと思ったら、私はそうします。最短の歩行アルゴリズムを実装できるかどうかを確認したかったので、まだバグがあると確信しています。

1

私はこの問題を_2^N_時間で解決する解決策がありますが、これは貧弱ですが、問題をフレーミングするのに役立つ方法だと思うので、投稿すると思いました。

問題をグラフとしてモデル化するのではなく、二分決定木(Tなど)としてモデル化します。各レベルでは、右または左に行くことを選択する必要があります。各エッジの「コスト」を計算するのはかなり簡単です。 h(K)を現在のノードの高さKとし、次にEdgeのコストをleft_child(K) = h(K) x dist(K, left_child(K))とします。右の子のエッジのコストについても、同様の計算で十分です。このツリーを構築し、エッジの累積コストをずっと追跡し、総コストが最小のリーフノードへのパスを報告します。

各Edgeの長さdist(K, left_child(K))は次のサイトに移動する時間を表すので、コスト計算が機能することに注意してください。サブツリーの高さは、残っているサイトの数です(たとえば、まだ放射線を放出しています)。

このフレームワーク内の秘訣は、ブランチに沿って検索を拡張することを無視できることを「証明」するために使用できるヒューリスティックがあるかどうかを判断することです。私の直感は、そのようなヒューリスティックにはそれを打ち負かすサイトの配置があるが、おそらく誰かが何かを思いつくことができるということです。

グラフに最短経路ソリューションを適用することを提案している人はたくさんいますが、そのようなソリューションが機能するかどうかについては、いくつか疑問があります。問題の「グラフ」内の隣人は、あなたがたどる経路に応じて変化します。たとえば、_[-12, -2, 3, 7]_を使用した元の投稿では、_-2_に移動すると_-12_と_3_が「隣人」になり、_3_に移動すると_-2_と_7_は隣人です。正の値と負の値のすべての可能な「ペア」は、最終的なグラフでは潜在的に数時間になる可能性があります。動的グラフで明らかに正しいと思われる最短経路アルゴリズムは知りません。

1

すべてのステージを、最も近いバレルに右に行くか、最も近いバレルに左に行くかのバイナリ選択と考えるのが最も理にかなっていると思います。モーションを作成することにより合計で発生する放射線ユニットの数を詳細に示すコスト関数を用意し、コストが最も低いものを選択します。

単純に最も近いバレルを考慮するのではなく、バレルから離れると、効果的に2倍の放射線を追加していると想定します。なぜなら、離れると、後でその方向に戻る必要があるというコストもかかるからです。

[-12、-2,3,7]の例では、左に移動すると、左側に合計14(2 + 2 + 10)、右側に18(2 + 2 + 5 + 9)が発生します。合計22です。右に移動すると、右側に10(3 + 3 + 4)、右側に26(3 + 3 + 5 + 15)が発生します。明らかに、左側は最初は正しい解決策です。同様の計算は、すべての連続する動きに対して行うことができます。

その後、問題は基本的に検索に減少するため、複雑度はO(nlog(n))になるはずです。これはO(n!)よりはるかに優れています。これは、基本的には比較ベースの検索アルゴリズムであり、O(nlog(n))よりも優れた方法ではないため、この問題に存在する可能性のある最低の複雑さであると私は信じています

どうやら私はこの説明では十分に明確ではなかったので、もう少しプログラマティックにすることにしました。1。左に行くことによって発生するコストと、現在の位置に基づいて右に行くことによって発生するコストを計算します。最も安価な方向3.方向に移動するコストを計算する際に、到達したバレルを考慮から外します

コストの計算:1.指定された方向で最も近いバレルを特定します。 $ distが、現在の位置から指定された方向の最も近いバレルまでの距離であるとしましょう。 2.コストはN * $ distとして初期化され、Nはまだアクティブなバレルのみを考慮します。 3.これに、$ distで示される新しい位置が、残りのすべてのバレルからの距離を追加します。

0

パスが複雑である限り、文字列が2 * N ^ 2タプル(boolean、int、int、int、string)を維持する幅優先検索を使用して解決できると思います。

タプルは(最小または最大のブール値、最小の移動位置、最大の移動位置、放出された総放射、経路履歴)です。

アルゴリズムは次のようになります。

  1. タプルのプールを単一のエントリに初期化します(min、0、0、0、 "")
  2. 放射が最小限のプール内の要素を見つけます。最小値と最大値がすべてのバレルの最小値と最大値に対応している場合、パス履歴が最適なソリューションです。それ以外の場合は、プールから削除します。
  3. このタプルの2つの子孫を計算します。それぞれが次の未処理のバレルに向かって左または右に歩くことに対応します。
  4. 子孫をプールに挿入します。新しい子孫と同じブール値、最小値、最大値を持つ要素がプール内に既に存在する場合は、放射数の多い要素を破棄します。
  5. 移動2。

支配的なタプルを見つけて削除すると、パフォーマンスが劇的に向上します。各タプルに「has bred」フラグを追加し、プールにブリードされたタプルを残すことは価値があるかもしれません。

また、タプルを格納する方法を決定する際に行われるべき重要な決定がいくつかあり、それらを支配およびブリードする新しい要素を検索します。

0
NovaDenizen

部分的な解決策-後で戻ってきます。

「デフォルト」の戦略は、左または右、どちらか安い方で実行されると仮定します。さて、1バレルをピックアップするために、もう一方のサイドトリップをする価値はありますか。答えを計算するのはかなり簡単です。

入力サンプルの場合、完全に正しく実行する方が、左に完全に実行するよりも安価です。サイドトリップの価値は-2ですか?完全に実行してから0に戻るコストを14まで減らします(デフォルトの戦略では、1移動あたり4放射線ユニットを0から3に「支払っていた」ため、3に減り、3から3を支払っていました。 7になり、現在は2になります)。さらに、移動ごとに1ずつ減少し、0から-2に移動するためのコストが削減されるため、さらに2を節約し、合計で16になります。

ただし、(16-14)= 2の正味ゲインの場合、-2に移動してから0に14(0に移動するごとに4ユニット、0に移動するごとに3ユニット)のコストが追加されます。これを計算するために、各決定について問題全体を解決する正確なコストを評価する必要がないことに注意してください-左端まで実行することが右端まで実行するよりも安いかどうか、およびその方法を知るだけで決定するのに十分な情報があります多くの廃棄物コンテナがあなたの両側にあり、最も近い2までの距離です。つまり、O(N ^ 2)です。

1つの重要な問題を除いて-私はあなたが最後まで走り続けると仮定しました、そして私たちはあなたが倍に戻るかもしれないことを知っています。それを整理するために、計算を更新する必要があります。サンプル入力の場合、0から7まで実行している間、1秒あたりの単位あたり1少ない総放射を放出することにより、14を節約すると想定しました。ただし、7に実行する前に2倍に戻すと、節約額は減少します。

それはかなり悪いことです。なぜなら、すべての可能性を試さずに次のダブルバックを計算する方法がわからないため、O(2 ^ N)に戻るからです。

例外-刈り込みで2 ^ Nです。 -2への「サイドトリップ」のコストは14と計算しましたが、右端の数に到達する前にサイドトリップがなければ16増加しました。一番右の数が5だったとしたら、-2へのサイドトリップが報われなかったことはすぐにわかります。 (まだ費用14、最大利益12)。 -2に行ってから、6に到達する前にサイドトリップを行うことを検討する必要もありません。なぜなら、そもそもそのポイントにまっすぐ進むよりも常に劣るからです。

0
psr