これがNP完全問題に取り組んでいるのではないかと心配しています。誰かが私にそれがそうであるかどうかについて答えを与えることができることを願っています。そして、私はただ「はい」または「いいえ」よりも多くの答えを探しています。理由を知りたいのですが。 「これは基本的にこの問題 'x'であり、NP完全ではありません。(ウィキペディアのリンク)」と言えます。
(いいえ、これは宿題ではありません)
2つの点が任意の無向グラフで接続されているかどうかを判断する方法はありますか?例:次の
Well
|
|
A
|
+--B--+--C--+--D--+
| | | |
| | | |
E F G H
| | | |
| | | |
+--J--+--K--+--L--+
|
|
M
|
|
House
ポイントAからM(「I」なし)は、開閉可能な制御ポイント(天然ガスパイプのバルブなど)です。 '+'はノード(パイプTのような)であり、WellとHouseもノードであると思います。
井戸と家がまだ接続されているかどうか(他の制御点も閉じている可能性があります)、任意の制御点(Cなど)を閉じたかどうかを知りたいです。たとえば、B、K、Dが閉じている場合でも、A-E-J-F-C-G-L-Mを通るパスがあり、Cを閉じるとウェルとハウスが切断されます。もちろん; Dだけが閉じられた場合、Cだけを閉じてもハウスは切断されません。
別の言い方をすれば、Cはブリッジ/カットエッジ/峡部ですか?
各コントロールポイントをグラフ上の重みとして扱うことができます(開いている場合は0、閉じている場合は1)。次に、WellとHouseの間の最短パスを見つけます(結果> = 1は、それらが切断されたことを示します。最短パスを見つけるためのアルゴリズムを短絡する方法はいくつかあります(たとえば、1に達したらパスを破棄し、停止します)。井戸と家などを結ぶ経路ができたら検索します。もちろん、あきらめる前にチェックするホップの数に人為的な制限を設けることもできます。
誰かが以前にこの種の問題を分類したに違いありません、私はただ名前を逃しています。
http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm を参照してください。これは、グラフに関連するすべての問題のワンストップショップです。あなたの問題は実際には二次時間で解決できると思います。
あなたの説明は、最短経路を見つけるのではなく、2つのノードが接続されているかどうかだけに関心があることを示しているようです。
2つのノードが接続されているかどうかを確認するのは比較的簡単です。
Create two sets of nodes: toDoSet and doneSet
Add the source node to the toDoSet
while (toDoSet is not empty) {
Remove the first element from toDoSet
Add it to doneSet
foreach (node reachable from the removed node) {
if (the node equals the destination node) {
return success
}
if (the node is not in doneSet) {
add it to toDoSet
}
}
}
return failure.
ToDoSetとdoneSetにハッシュテーブルなどを使用する場合、これは線形アルゴリズムだと思います。
このアルゴリズムは基本的に、マークアンドスイープガベージコレクションのマーク部分であることに注意してください。
この問題にはダイクストラのアルゴリズムは必要ありません。これは、不要なヒープを使用し、複雑さにlog(N)の係数を導入するためです。これは幅優先探索です。閉じたエッジをエッジとして含めないでください。
最短経路を見つける問題はNP完全ではありません。これは最短経路問題(元々は十分)と呼ばれ、さまざまなバリエーションを解くための アルゴリズム があります。
2つのノードが接続されているかどうかを判断する問題も、NP完全ではありません。いずれかのノードから開始する深さ優先探索を使用して、他のノードに接続されているかどうかを判断できます。
nP完全ではなく、よく知られた解決策で解決- ダイクストラのアルゴリズム
私にはあなたが解決策に取り組んでいるように見えますが、私が問題を誤解した可能性があります。あなたが言うように、閉じたエッジ1を重みとして与える場合は、ダイクストラのアルゴリズムを適用することができます http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm 。これにより、O(E * lg(V))の問題が解決するはずです。
隣接行列があると仮定します。
bool[,] adj = new bool[n, n];
ここで、iとjの間にオープンパスがあり、bool [i、i] = falseの場合、bool [i、j] = trueです。
public bool pathExists(int[,] adj, int start, int end)
{
List<int> visited = new List<int>();
List<int> inprocess = new List<int>();
inprocess.Add(start);
while(inprocess.Count > 0)
{
int cur = inprocess[0];
inprocess.RemoveAt(0);
if(cur == end)
return true;
if(visited.Contains(cur))
continue;
visited.Add(cur);
for(int i = 0; i < adj.Length; i++)
if(adj[cur, i] && !visited.Contains(i) && !inprocess.Contains(i))
inprocess.Add(i);
}
return false;
}
上記のアルゴリズムの再帰バージョン(Rubyで記述)は次のとおりです。
def connected? from, to, edges
return true if from == to
return true if edges.include?([from, to])
return true if edges.include?([to, from])
adjacent = edges.find_all { |e| e.include? from }
.flatten
.reject { |e| e == from }
return adjacent.map do |a|
connected? a, to, edges.reject { |e| e.include? from }
end.any?
end
2つのノードが接続されているかどうかを判断するだけでよい場合は、代わりにセットを使用できます。これは、グラフアルゴリズムよりも高速です。
最初は、ノードはそれぞれのセットに含まれます。
o o1 o o o o o o2
\ / \ / \ / \ /
o o o o o o o o
\ / \ /
o o o o o o o o
\ /
o o1 o o o o o o2
アルゴリズムが進行してセットをマージすると、入力が比較的半分になります。
上記の例では、o1とo2の間にパスがあるかどうかを確認していました。このパスは、すべてのエッジをマージした後の最後にのみ見つかりました。一部のグラフには個別のコンポーネント(切断されている)が含まれている場合があり、これにより、最後に1つのセットを設定することができなくなります。このような場合、このアルゴリズムを使用して、接続性をテストし、グラフ内のコンポーネントの数をカウントすることもできます。コンポーネントの数は、アルゴリズムが終了したときに取得できるセットの数です。
可能なグラフ(上のツリーの場合):
o-o1-o-o-o2
| |
o o
|
o
間違いなくNP完全ではないという回答がありますが、これも非常に古い質問です。
ただし、問題を調べるための別のアプローチを提案します。これには互いに素なセットを使用できます。ほとんどの場合、特定のシナリオでは、このアプローチにより、グラフトラバーサルを実行するよりも時間が長くなります(これには、テストの大部分に対して一定時間が含まれます) )。ただし、ランクによる結合またはパス圧縮が使用されている場合、グラフの作成にはかなりの時間がかかる可能性があります。
データ構造について読むことができます ここ 。
ダイクストラ法はやり過ぎです! Aからの幅優先探索を使用して、到達したいノードを検索します。見つからない場合は接続されていません。複雑さは、検索ごとにO(nm)であり、ダイクストラよりも小さいです。
やや関連しているのは、最大フロー/最小カットの問題です。それを調べてください、それはあなたの問題に関連しているかもしれません。