3

アイテムのペアの複数のリストがあるシナリオを考えると、たとえば次のようになります。

  1. {12,13,14,23,24}
  2. {14,15,25}
  3. {16,17,25,26,36}

ここで、12 はアイテム '1' と '2' のペアです (したがって、21 は 12 に相当します)。単一のアイテムが存在しないように、各リストからアイテムのペアを選択できる方法の数を数えたいと考えています。繰り返した。各リストからペアを 1 つだけ選択する必要があります。各リスト内のアイテムの数とリストの数は任意ですが、リストごとに少なくとも 1 つのアイテムのペアを持つリストが少なくとも 2 つあると想定できます。そして、ペアは有限のアルファベットの記号から作られ、数字[1-9]を想定しています。また、リストに重複ペア {12,12} または {12,21} を含めることも、対称ペア {11} を含めることもできません。

より具体的には、上記の例で、最初のリストからアイテムのペア 14 を選択した場合、2 番目のリストの選択肢は 25 だけです。これは、14 と 15 に「1」が含まれているためです。したがって、16 と 17 には「1」が含まれ、25 と 26 には「2」が含まれるため、3 番目のリストからの唯一の選択肢は 36 です。

リストにはそれぞれ何百ものアイテムのペアが含まれている可能性があるため、選択肢のすべての順列を通過せずに「これは有効な選択ですか?」と尋ねることなく、アイテムのペアの合計組み合わせをカウントする効率的な方法を知っている人はいますか?


アップデート

これにしばらく時間を費やした後、どのリストも異なるペアを共有していない場合、組み合わせの数を数えるのは簡単であることに気付きました。ただし、異なるペアが 2 つ以上のリスト間で共有されるとすぐに、組み合わせ式は適用されません。

今のところ、すべてのリストに同じアイテムのペアがある組み合わせの数を数える方法があるかどうかを把握しようとしています (力ずくではなく組み合わせ数学を使用)。例えば:

  1. {12,23,34,45,67}
  2. {12,23,34,45,67}
  3. {12,23,34,45,67}
4

7 に答える 7

3

問題は #P-complete です。これは NP 完全よりもさらに困難です。これは、SAT のインスタンスに対する満足のいく割り当ての数を見つけるのと同じくらい難しいことです。

削減はパーフェクト マッチングからです。エッジのセットである が頂点のペア (エッジによって接続されているペア) のリストであるグラフG = {V, E}があるとします。次に、 のコピーをE持つことにより、「アイテムのペア」のインスタンスをエンコードします。つまり、頂点の数の半分に等しい数のコピーがあります。ここで、あなたの場合の「ヒット」は、頂点が繰り返されていないエッジに対応し、すべての頂点がカバーされたことを意味します。これが完全一致の定義です。そして、完全に一致するものはすべてヒットします。これは 1 対 1 の対応です。|V|/2EE|V|/2|V|

于 2009-06-12T15:59:31.037 に答える
2

リスト内のすべての要素がグラフ内のノードであるとしましょう。2つのノードを一緒に選択できる場合は、2つのノードの間にエッジがあります(共通の記号はありません)。同じリストの2つのノード間にエッジはありません。n個のリストがある場合、問題はこのグラフでサイズnのクリークの数を見つけることです。n要素よりも大きいクリークはありません。そのようなクリークが少なくとも1つ存在するかどうかを調べることがnp完全であることを考えると、この問題はnp完全だと思います。参照: http: //en.wikipedia.org/wiki/Clique_problem

指摘したように、この問題を解くことでクリーク問題を解き、これがNP完全であることを示すことができることを証明する必要があります。必要なセットの数、つまりnサイズのクリークの数を数えることができれば、サイズnのクリークが少なくとも1つあるかどうかがわかります。残念ながら、サイズnのクリークがない場合、サイズk<nのクリークがあるかどうかはわかりません。

もう1つの質問は、この問題で任意のグラフを表現できるかどうかです。はいと思いますが、よくわかりません。

これはまだNP完全だと思います

于 2009-06-11T20:53:17.937 に答える
1

セットAで選択されたアイテムを前提として、セットBのアイテムを使用できるかどうかを判断するために評価する必要がある関数があるため、ブルートフォース以外に実行できる計算はありません。単純な組み合わせ計算ではありません。仕事。

メモ化とハッシュを使用すると、計算を1〜2桁高速化できます。

メモ化は、同様のブルートフォースパスの以前の結果を記憶しています。リストnにいて、すでにシンボルx、y、zを消費していて、以前にこの状況に遭遇した場合は、残りのリストから同じ数の可能な組み合わせを追加します。x、y、zを使用してnをリストする方法は関係ありません。したがって、キャッシュされた結果がある場合はそれを使用するか、計算を次のリストに続けて確認します。ブルートフォース再帰アルゴリズムを作成して結果を計算し、結果をキャッシュする場合、これはうまく機能します。

保存された結果の鍵は、現在のリストと使用された記号です。記号を並べ替えてキーを作成します。ここでは、辞書または辞書の配列が理にかなっていると思います。

ハッシュを使用して、各リストで検索する必要のあるペアの数を減らします。リストごとに、特定の数のシンボルがすでに消費されている場合に使用できるペアのハッシュを作成します。使用するメモリの量と事前計算に費やす時間に基づいて、ハッシュで使用する消費シンボルの数を選択します。1〜2個の記号を使用するとよいと思います。これらのハッシュをアイテムの数で並べ替えます...昇順で、上位nを維持します。ハッシュによって作業が少ししか減らない場合は、おそらく保持する価値がないため、残りを破棄すると言います(ハッシュが多い場合は、ハッシュを見つけるのに時間がかかります)。したがって、リストを調べているときに、リストのハッシュをすばやくスキャンして、ハッシュでシンボルを使用したかどうかを確認できます。あなたが持っている場合、次に、表示された最初のハッシュを使用してリストをスキャンします。最初のハッシュには、スキャンするペアが最も少なくなります。あなたが本当に便利なら、あなたは行くにつれてこれらのハッシュを構築することができ、それをするために前もって時間を無駄にすることはないかもしれません。

ハッシュを投げてツリーを使用できるかもしれませんが、ツリーを埋めるには長い時間がかかると思います。

于 2009-06-12T20:12:47.260 に答える
1

すべての組み合わせを生成したい場合、制約プログラミングは優れたアプローチです。試してみるために、Gecode (バージョン 3.2.2) を使用してモデルを作成し、問題を解決しました。上記の 2 つの例は非常に簡単に解決できますが、他の例は難しい場合があります。いずれにせよ、生成してテストするよりも優れているはずです。

/*
 *  Main authors:
 *     Mikael Zayenz Lagerkvist <lagerkvist@gecode.org>
 *
 *  Copyright:
 *     Mikael Zayenz Lagerkvist, 2009
 *
 *  Permission is hereby granted, free of charge, to any person obtaining
 *  a copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject to
 *  the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
#include <gecode/driver.hh>
#include <gecode/int.hh>
#include <gecode/minimodel.hh>

using namespace Gecode;

namespace {
  /// List of specifications
  extern const int* specs[];
  /// Number of specifications
  extern const unsigned int n_specs;
}


/**
 * \brief Selecting pairs
 *
 * Given a set of lists of pairs of values, select a pair from each
 * list so that no value is selected more than once.
 *
 */
class SelectPairs : public Script {
protected:
  /// Specification
  const int* spec;
  /// The values from all selected pairs
  IntVarArray s;
public:
  /// The actual problem
  SelectPairs(const SizeOptions& opt)
    : spec(specs[opt.size()]),
      s(*this,spec[0] * 2,Int::Limits::min, Int::Limits::max) {

    int pos = 1; // Position read from spec
    // For all lists
    for (int i = 0; i < spec[0]; ++i) {
      int npairs = spec[pos++];
      // Construct TupleSet for pairs from list i
      TupleSet ts;
      for (int p = 0; p < npairs; ++p) {
        IntArgs tuple(2);
        tuple[0] = spec[pos++];
        tuple[1] = spec[pos++];
        ts.add(tuple);
      }
      ts.finalize();

      // <s[2i],s[2i+1]> must be from list i
      IntVarArgs pair(2);
      pair[0] = s[2*i]; pair[1] = s[2*i + 1];
      extensional(*this, pair, ts);
    }

    // All values must be pairwise distinct
    distinct(*this, s, opt.icl());

    // Select values for the variables
    branch(*this, s, INT_VAR_SIZE_MIN, INT_VAL_MIN);
  }

  /// Constructor for cloning \a s
  SelectPairs(bool share, SelectPairs& sp) 
    : Script(share,sp), spec(sp.spec) {
    s.update(*this, share, sp.s);
  }

  /// Perform copying during cloning
  virtual Space*
  copy(bool share) {
    return new SelectPairs(share,*this);
  }

  /// Print solution
  virtual void
  print(std::ostream& os) const {
    os << "\t";
    for (int i = 0; i < spec[0]; ++i) {
      os << "(" << s[2*i] << "," << s[2*i+1] << ") ";
      if ((i+1) % 10 == 0)
        os << std::endl << "\t";
    }
    if (spec[0] % 10)
      os << std::endl;
  }
};

/** \brief Main-function
 *  \relates SelectPairs
 */
int
main(int argc, char* argv[]) {
  SizeOptions opt("SelectPairs");
  opt.iterations(500);
  opt.size(0);
  opt.parse(argc,argv);
  if (opt.size() >= n_specs) {
    std::cerr << "Error: size must be between 0 and "
              << n_specs-1 << std::endl;
    return 1;
  }
  Script::run<SelectPairs,DFS,SizeOptions>(opt);
  return 0;
}

namespace {
  const int s0[] = {
    // Number of lists
    3,
    // Lists (number of pairs, pair0, pair1, ...)
    5,  1,2,  1,3,  1,4,  2,3,  2,4,
    3,  1,4,  1,5,  2,5,
    5,  1,6,  1,7,  2,5,  2,6,  3,6
  };

  const int s1[] = {
    // Number of lists
    3,
    // Lists (number of pairs, pair0, pair1, ...)
    5,  1,2,  2,3,  3,4,  4,5,  6,7,
    5,  1,2,  2,3,  3,4,  4,5,  6,7,
    5,  1,2,  2,3,  3,4,  4,5,  6,7
  };

  const int *specs[] = {s0, s1};
  const unsigned n_specs = sizeof(specs)/sizeof(int*);
}
于 2009-12-16T13:23:39.067 に答える
1

問題は非常に単純に見えますが、NP-complete Set Cover Problemに関連している可能性があります。そのため、有効な組み合わせを検出する効率的な方法がない可能性があります。したがって、それらをカウントする効率的な方法はありません。

アップデート

問題を攻撃しにくくしているように見えるので、リスト項目がペアになっていると考えました.1つの項目に対して2つのプロパティをチェックする必要があります. そこで、ペアをスカラー項目に減らす方法を探し、方法を見つけました。

nシンボルのセットを最初のn素数のセットにマップします。この関数を呼び出しますM。シンボルの場合09次のマッピングを取得しますM(4) = 11。たとえば、次のようになります。

{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} => {2, 3, 5, 7, 11, 13, 17, 19, 23, 29}

これで、写像 X を使用してペアをと(n, m)の写像の積に写像できます。これにより、ペアが に変わります。nm(2, 5)X((2, 5)) = M(2) * M(5) = 5 * 13 = 65

X((n, m)) = M(n) * M(m)

なぜこれが?2 つのペアが(a, b)あり(c, d)、2 つのリストから、マッピングを使用してそれらをマッピングXxy乗算すると、x * y = M(a) * M(b) * M(c) * M(d)4 つの素数の積が得られます。リストがあれば、各リストからペアを選択することで、より多くの因数で積を拡張し、2w素数の積を取得できwます。最後の質問は、この積は、選択して乗算したペアについて何を教えてくれるでしょうか? 選択されたペアが有効な選択を形成する場合、1 つのシンボルを 2 回選択することはありません。したがって、積には素数が 2 回含まれず、正方形はありません。選択が無効な場合、製品には少なくとも 1 つの素数が 2 回含まれており、正方形がありません。そして、ここで最後の例です。

X((2, 5)) = 5 * 13 = 65
X((3, 6)) = 7 * 17 = 119
X((3, 4)) = 7 * 11 = 77

選択25して36降伏65 * 119 = 7735 = 5 * 7 * 13 * 17し、正方形がないため、有効です。選択36して34降伏119 * 77 = 9163 = 7² * 11 * 17し、四角形ではないため、無効です。

また、これが対称性 - X((m, n)) = X((n, m)) - をいかにうまく保持しているかにも注意してくださいX((m, m)) = M(m) * M(m)

参考になるかわかりませんが、今ならわかるので考えてみてください(^^)


これは、3-SAT 問題をこの問題に還元する最初の部分です。3-SETの問題は次のとおりです。

(!A | B | C) & (B | !C | !D) & (A | !B)

そして、これが私が得た限りの削減です。

  • mn はペアを表す
  • 行はリストを表します
  • アスタリスクは、任意の一意の記号を表します

A1-A1'    !A1-!A1'     => Select A true or false
B1-B1'    !B1-!B1'     => Select B true or false
C1-C1'    !C1-!C1'     => Select C true or false
D1-D1'    !D1-!D1'     => Select D true or false

A1-*   !B1-*   !C1-*   => !A | B | C

A2-!A1'   !A2-A1'      => Create a copy of A
B2-!B1'   !B2-B1'      => Create a copy of B
C2-!C1'   !C2-C1'      => Create a copy of C
D2-!D1'   !D2-D1'      => Create a copy of D

!B2-*  C2-*    D2-*    => B | !C | !D

(How to perform a second copy of the four variables???)

!A3-*  B3-*

私 (または他の誰か) がこの削減を完了し、一般的なケースでそれを行う方法を示すことができれば、これは問題の NP 完全を証明します。変数をもう一度コピーすることに固執しています。

于 2009-06-11T20:30:03.517 に答える
0

これは、制約プログラミングアプローチを適用するのに適した問題のように思えます。ウィキペディアが提供するパッケージのリストに、過去にGecodeを使用した経験があることを付け加えておきます。Gecode の例は、制約プログラミングの基本的なチュートリアルも提供します。 Constraint Processingは、アルゴリズムがどのように機能するかをより深く掘り下げたい場合に適した本です。

于 2009-06-11T20:47:35.690 に答える
0

最初に試してみてください.これは、ブルートフォースよりも平均的な複雑さが改善されたアルゴリズムです。基本的に、各反復で長さが増加する文字列を作成します。これは最善の解決策ではないかもしれませんが、最善の解決策が見つかるまで待ちます... :)

リスト 1 から始めます。そのリストのすべてのエントリは、長さ 2 (#=5) の有効なソリューションです。次に、リスト 2 を導入するとき、{1425、2314、2315 になる長さ 4 のすべての有効なソリューションの記録を保持します。 、2415} (#=4)。

3 番目のリストをミックスに追加したら、このプロセスを繰り返します。{142536, 241536} (#=2) になります。

各反復で悪い文字列を捨てているため、複雑さが軽減されます。最悪のシナリオはたまたま同じで、すべてのペアが異なる場合です。

于 2009-06-11T20:31:13.480 に答える