18

今日、友人から課題の問題について質問がありました。非常に簡単な解決策を見つけましたが、それをより簡単かつ迅速に行うことができると感じています。あなたの助けをいただければ幸いです。

問題:私がN人いると仮定すると、それらをM棟に割り当てる必要があり、各建物にはK人を収容できます。すべての人がお互いに住むことをいとわないわけではないので、私はN * Nセルのマトリックスと、お互いに住むことをいとわない人々を示す1を持っています。セルに1が含まれている場合、それはIとJが一緒に住むことができることを意味します。明らかに、行列は主対角線を中心に対称です。

私の解決策は次のとおりです(擬似コード):

int[] Match(int[] people, int[][] pairs, int numBuildings, int buildingsSize)
{
    int[] freePeople = findFreePeople(people);
    if(freePeople) = 0 
    {
        return people;
    }

    foreach(int person in freePeople)
    {
        for(int buildingIndex=0 to numBuildings)
        {
            if( CheckIfPersonFitsInBuilding(...) )
            {
                int[] tempPeople = people.Copy();
                tempPeople[person] = buildingIndex;
                int[] result = Match(tempPeople,pairs,numBuildings,buildingsSize);
                if(result != null)
                {
                    return result;
                }
            }
        }
    }
    return null;
}

再帰を使用して可能なすべての配置をカバーします。これは大幅に最適化できると思います。ヒューリスティックではなく、はるかに複雑さの少ないソリューションについて話します。

  1. これに似た正式なよく知られた問題はありますか?
  2. より良いアルゴリズムはありますか?

よくわかりませんが、これは安定結婚問題に関係しているのではないかと思います。

4

3 に答える 3

25

この問題は、グラフをクリークに分解するNP 完全問題(クリーク カバー問題)からの還元により、NP 困難であることが知られています。

まず、いくつかの用語と説明です。グラフ内のクリークは、各ノードがクリーク内の他のノードに接続されている k 個の異なるノードのセットです。グラフ内の独立セットは、2 つのノードが互いに接続されていない k 個の異なるノードのセットです。任意のグラフ G を取り、エッジが欠落している場合は常にエッジを導入し、以前に存在したすべてのエッジを削除すると、元のグラフの補グラフが得られます。これは、初期グラフでクリークを見つける問題が、補グラフで独立集合を見つけることと同じであることを意味します。

これが興味深い理由は、あなたが説明している問題では、各エッジが「この 2 人を一緒に収容することはできない」ことを示す人々のグラフが与えられているからです。したがって、あなたが説明している問題は、グラフをそれぞれが独立した集合である k 個のサブグラフに分割する方法を見つけようとしていると考えることができます。このグラフの補数を作成すると、問題のないすべての人が一緒に配置されたグラフが得られます。その場合、グループをすべてクリークである k 個のグループに分割します。

次の問題は NP 完全であることが知られています。

グラフと数値 k が与えられた場合、グラフ内のノードを k 個のクリークに分割できますか?

この問題を多項式時間の問題に還元でき、問題が NP 困難であることを示します。構成は単純です。最初のグラフ G と数 k が与えられた場合、最初に G の補数を構成します。これは、補数を k 個の独立した集合に分割できる場合、元のグラフ G を k 個のクリークに分割できることを意味します (なぜなら、クリークと独立集合の間の双対性について)。ここで、この新しいグラフを取得して、ノードごとに 1 人の人物のセットに変換します。元のグラフでノードが接続されている場合、2 人の人物を同じ部屋に配置することはできません。さて、もし G が k クリークに分解できれば、G の補集合が k 個の独立した集合に分解できるなら、これらの人々を k 家に分配する方法があります。その結果、クリーク カバーの既知の NP 完全問題は、多項式時間の問題に還元できるため、問題は NP 困難です。独立したセットが家に収まるようにするには、各部屋の最大収容人数をグラフのノード数 n に設定します。これにより、独立したセットをどの部屋にも収容できます。

問題はNP困難であるため、P = NPでない限り、多項式時間の解はありません。したがって、誰もが知っているように、多項式時間アルゴリズムはなく、バックトラッキング再帰が最適なソリューションである可能性があります。

お役に立てれば!

于 2012-06-23T20:45:57.777 に答える
13

templatetypedef は、なぜ問題が NP 困難であり、(既知の) 多項式時間解を持たないかについて非常に優れた証明を与えました。

ただし、多くの NP 困難な問題と同様に、それは実際には効率的に解決できない、またはブルート フォース ソリューションを改善できないという意味ではありません。

特に、制約充足問題を調べる必要があります。それらは、解決しようとしていることを正確に説明する、より一般的な問題のクラスです: 一連の制約が与えられた場合、すべての制約を満たす値は何ですか?

AIMAには、これらのタイプの問題を解決する方法についての非常に優れた章があります。そこには多くの優れた情報があり、本は学部レベル向けに設計されているため、非常にアクセスしやすいので、それを読むことをお勧めします. ここでいくつかの大きなアイデアを紹介します。

主な質問は次のとおりです。

  • あなたの再帰で次に割り当てられるべき学生はどれですか?
  • その生徒にとって、建物はどのような順序で検討されるべきですか?

これには、次の 2 つのヒューリスティックがあります。

  • 残りの最小値(MRV) ヒューリスティック: 再帰で次に建物に割り当てる生徒を選択するときは、残りの選択肢が最も少ない生徒を選択します。
  • 最小制約値(LCV) ヒューリスティック: どの生徒を見るかを決定した後、残りの生徒の選択肢が最も少ない建物を割り当てます。

MRV ヒューリスティックの場合、他の学生に対する制約が最も多い学生を選択して、関係を断ち切ります。これらのヒューリスティックの背後にある考え方は、成功する可能性が最も高い (LCV) 検索パスを選択することです。ただし、特定の検索パスが与えられた場合、そのパスで費やされる時間 (MRV) を減らすために、できるだけ早く失敗する必要があります。

また、基本的な順方向チェックによる単純な再帰の代わりに、AC-3 のような、より先を見据えたより高度な検索アルゴリズムを使用する必要があります。

制約充足の問題は多くのソフトウェア エンジニアリング アプリケーションで非常に一般的であるため、それらを効率的に解決できる多数のオープン ライブラリが既に存在します。もちろん、これは、解決しようとしている問題が実際のアプリケーションのためのものであり、宿題のようなものではないことを前提としています。

于 2012-06-27T20:25:11.953 に答える
4

これらの問題を解決する良い方法は、有限領域の制約ソルバーを使用することです。

たとえば、GNU-Prolog を使用すると、次のようになります。

solve(Out):-
    People = [Jon, Mary, Alice, Smith, Dick, George, Betty, Lucy],
    fd_domain(People, 0, 3),    % people lives in buildings 0 to 3.
    fd_atmost(4, People, 0),    % at most, 4 people may live in building 0
    fd_atmost(3, People, 1),    % at most, 3 people may live in building 1
    fd_atmost(2, People, 2),    % etc.
    fd_atmost(1, People, 3),
    Jon   #\= Mary,             % Jon hates Mary
    Alice #\= Smith,            % etc.
    Betty #\= Lucy,
    Jon   #\= Alice,
    Dick  #\= George,
    fd_labeling(People),        % iterate until an acceptable combination is found.
    People = Out.

:- solve(O), write(O), nl.

複雑さの観点からは、これは引き続き NP 完全です。ただし、制約ソルバーは、ラベル付けステップで割り当てが実行される方法を並べ替えて、行き止まりが早期に発見されるようにし、検索ツリーを小さくする場合があります。

于 2012-06-24T00:41:29.627 に答える