2011-01-27 14 views
4

私は面白い問題に直面しています。私は(かなり大きい)ブロック数を持っています。ブロックは単にオフセットから始まり、長さと色を持つものです。オフセットと長さは制限されています。これらのブロックが存在するスペースは、< 0-N>です(Nは数十万から数百万の範囲です)。無効なブロックは、オフセットがNより大きい、またはオフセットと長さの合計がNより大きいブロックです。ブロックには約16種類の色があります(そのうちの1つだけです)。小さな重なりブロックをより大きな連続ブロックにマージするための効率的なアルゴリズム?

ブロックの数千人があるかもしれませんし、状況は次のように常にあります

block_X:オフ:100、LEN:50、色:青
block_Y:オフ:148、LEN:50 、色:青
block_Z:オフ:200、LEN:30、色:

赤あなたが見ることができるように、X及びYブロックは、この、その結果、単一の大きなブロックに接続することができます。

block_XY:オフ:100、98をlenは、色:青
block_Z:200オフ、30をlenは、色:赤

私はすべてを行くだろうアルゴリズムを作成したいです重複して同じ色を持つブロックを接続します。実際には、ブロック間の隙間がかなり小さい場合(定数は約16かそこらで選択できますが、任意の数でもかまいません)、とにかくそれらのブロックを接続したいと思います。上記の例では、接続するブロックが2つしかないことに注意してください。実際には、接続可能なブロックの順序はずっと長くなります。

興味深いひねりもあり、このことを考慮してください。

block_Aを:オフ:100、LEN:200、色:青
block_Bを:オフ:200、LEN:200、カラー:ブルー
block_C:オフ:300、LEN:150、色:赤
block_D:オフ:400、LEN:200、色:青
block_E:オフ:500、LEN:200、色:青

あなたが見ることができるように、我々は一つの大きな青色のブロックにマージすることができます青いブロックの素敵な配列を有します。しかし、その真ん中に小さな赤いブロックがあります。このアルゴリズムをだますべきではない、正しい結果は次のとおり

block_ABDE:オフ:100、LEN:600、色:青
block_C:オフ:300、LEN:150、色:赤

データはstd :: multimapに格納されます。ここで、キーはオフセットで、値はブロックの長さと色を含む構造体です(multimap<uint32_t,pair<uint32_t, uint8_t> >)。同じオフセットから開始するブロックが存在する可能性があることに注意してください。しかし、このようなことが起こった場合、同じオフセットから始まるブロックは、異なる色と異なる長さを持つことが保証される。

誰もこの問題を効率的に解決するための良いアイデアを考え出すことができますか? アルゴリズムの目標は、ブロック数を減らすことですが、できるだけ小さくする必要はありません。

答えて

7

私は次のことをお勧めします:

  1. 始まり(オフセット)と終わりを計算し、各特定色の色
  2. それぞれに別々のリストを作成します(+オフセット長)すべてのブロック
  3. 各色固有のリストを先頭の値でソート
  4. 次に、各リストをトラバースして項目をマージします。次の項目の開始点が前の項目の終わりより小さいか等しい場合次のアイテムを削除し、 前回のもの。
6

ブロックのリストを各色のリストに分け、それらのリストのすべてをブロックの開始オフセットでソートします。 (実際には、色に基づいてフィルタリングしたり、オフセットでソートして、色で安定した並べ替えを行い、配列のパーティションで作業したりするとき、挿入ソートを行いたいと思うでしょう)。

最初のブロックから開始して、次のブロックのオフセットが現在のブロックの最後まで十分に近いかどうかを確認し、もしそうであればそれらをマージしてください。その後、リストの最後に進みます。

これで、各色のすべてのブロックを結合したので、リストを連結してすべての色のすべてのブロックの最終リストを取得できます。最も高価なステップ(漸近的に)はソートされるので、これはおそらく十分効率的です。この単純なアプローチのパフォーマンスを測定するまでは、配列やリンクされたリストよりも高度なデータ構造を使って、平均してより速いものを考え出すことができます。

2つのブロックをマージできるかどうかのルールは、1つのブロックのエンドポイントともう1つのブロックの開始ポイントにのみ依存し、ブロックのサイズには依存しないため、潜在的なマージはおそらくすべてのマージを識別し、マージがどのような順序で行われるかは関係ありません(つまり、マージは連想操作です)。

4

ブロックを各色ごとに1つのリストに分割する必要はありません。リスト全体をブロック開始アドレスでソートし、各色ごとに別々の{start、length}ペアを維持することで、単一パスで処理することができます。

+0

最初に色でソートしてから、オフセットでソートすることができます。 –

+0

しかし、なぜ迷惑? – TonyK

0

これは、例えば

青、それだけで、番号範囲のようである各色のように非常に簡単です:100から299、200-400、500から670まで、671から702まであなたにマージ

:青

:100-400、500から702

ただ、ソート範囲内の最初の値によると終了値(最後の要素過去実際には1)を見てください。それが次のものの開始以上であれば、それらはマージされます。

上記の300> 200のように、それらはマージするので、401 <500はそうしないので、671 == 671です。

各色について同じ操作を行います。

関連する問題