假設我們有涉及TopicID和StoryID, 與一對形成化合物主鍵列的SQL表TopicStory。
的目標是找到某種一套TopicID的組成。發佈的問題最多需要五個 。深度優先搜索 這些概述如下。
隨着搜索的深度限定在五,指出問題不能 比多項式複雜性更差。然而,要求爲最大的話題集合,可以與像 約束(選擇每個主題不相關的 任何其他選擇的主題至少兩層)可以發現一個普遍問題 可能是NP完全問題。
一詞的使用「搜索」中提出了一種回溯算法。在 以下,我們通過嵌套循環實現了回溯,其中每個循環是 ,由其外部的循環定義和參數化。
在我們給出詳細的細節之前,可能會激發描述 「蠻力」的方法,接下來可以更容易地理解更復雜的方法 。
BRUTE_FORCE:
Generate all possible subsets of five topics.
Test each of these sets for feasibility (each topic has
at least two stories unrelated to any of the other topics).
我們的深度優先搜索的草圖假設議題一共有排序, 例如按照TopicID的整數值排序。這允許生成主題 而不重複(由於主題的排列)。
NESTED_LOOPS:
(Loop_1) Select into List_1 all topics with at least two stories.
Iterate through List_1, choosing the first topic %T1%.
PASS control into Loop_2.
CONTINUE in Loop_1.
If the end of List_1 is reached, EXIT with failure.
(Loop_2) Select into List_2 all topics > %T1% with at least two
stories unrelated to %T1%.
Iterate through List_2, choosing the second topic %T2%.
If topic %T1% still has at least two stories unrelated
to %T2%, PASS control into Loop_3.
CONTINUE in Loop_2.
If the end of List_2 is reached, go BACK to Loop_1.
(Loop 3) Select into List_3 all topics > %T2% with at least two
stories unrelated to %T1% or %T2%.
Iterate through List_3, choosing the third topic %T3%.
If topic %T1% still has at least two stories unrelated
to %T2% or %T3%,
and topic %T2% still has at least two stories unrelated
to %T1% or %T3%, PASS control into Loop_4.
CONTINUE in Loop_3.
If the end of List_3 is reached, go BACK to Loop_2.
(Loop 4) Select into List_4 all topics > %T3% with at least two
stories unrelated to %T1%, %T2%, or %T3%.
Iterate through List_4, choosing the fourth topic %T4%.
If topic %T1% still has at least two stories unrelated
to %T2%, %T3%, or %T4%,
and topic %T2% still has at least two stories unrelated
to %T1%, %T3%, or %T4%,
and topic %T3% still has at least two stories unrelated
to %T1%, %T2%, or %T4%, PASS control into Loop_5.
CONTINUE in Loop_4.
If the end of List_4 is reached, go BACK to Loop_3.
(Loop 5) Select into List_5 all topics > %T4% with at least two
stories unrelated to %T1%, %T2%, %T3%, or %T4%.
Iterate through List_5, choosing the fifh topic %T5%.
If topic %T1% still has at least two stories unrelated
to %T2%, %T3%, %T4%, or %T5%,
and topic %T2% still has at least two stories unrelated
to %T1%, %T3%, %T4%, or %T5%,
and topic %T3% still has at least two stories unrelated
to %T1%, %T2%, %T4%, or %T5%,
and topic %T4% still has at least two stories unrelated
to %T1%, %T2%, %T3%, or %T5%, EXIT with success
returning five topics %T1%, %T2%, %T3%, %T4%, and %T5%.
CONTINUE in Loop_5.
If the end of List_5 is reached, go BACK to Loop_4.
使用「選擇」在每個嵌套循環的開口是爲了喚起 SQL查詢的可能性,以實現許多邏輯的。對於 例如最外層循環基本上是剛開結果集中 此查詢:
SELECT TS1.TopicID, Count(*)
From TopicStory TS1
Group By TS1.TopicID
Having Count(*) > 1
內部循環的相應的列表可以類似 通過SQL查詢取決於在 所選主題的參數值來構造外環。爲了說明沒有不必要的重複讓我們跳 權內部循環,並給出List_5適當的查詢:
SELECT TS5.TopicID, Count(*)
From TopicStory TS5
Where TS5.TopicID > %T4%
and NOT EXISTS (SELECT *
From TopicStory TSX
Where TSX.TopicID in (%T1%,%T2%,%T3%,%T4%)
and TSX.StoryID = TS5.StoryID
)
Group By TS5.TopicID
Having Count(*) > 1
這之後將在List_5檢查%T5%產生 計數至少兩個故事的左對於主題%T1%:
SELECT Count(*)
From TopicStory TZ1
Where TZ1.TopicID = %T1%
and NOT EXISTS (SELECT *
From TopicStory TX1
Where TX1.StoryID = TZ1.StoryID
and TX1.TopicID in (%T2%,%T3%,%T4%,TS5.TopicID)
)
並且對於其他先前話題選擇進行了必要的修改。
雖然它可能會降低性能不可接受,限制相關%T5%主題額外的邏輯 (使前面的話題選擇 仍然保留至少兩層的選擇)可以推入一個查詢。 它應該是這樣的:
/*
Given %T1%, %T2%, %T3$, and %T4% from queries above, find all topics %T5% > %T4%
with at least 2 stories not related to %T1%, %T2%, %T3%, or %T4% and such that
%T1% still has at least 2 stories not related to %T2%, %T3%, %T4%, or %T5% and
%T2% still has at least 2 stories not related to %T1%, %T3%, %T4%, or %T5% and
%T3% still has at least 2 stories not related to %T1%, %T2%, %T4%, or %T5% and
%T4% still has at least 2 stories not related to %T1%, %T2%, %T3%, or %T5%
*/
SELECT TS5.TopicID, Count(*)
From TopicStory TS5
Where TS5.TopicID > %T4%
and NOT EXISTS (SELECT *
From TopicStory TSX
Where TSX.TopicID in (%T1%,%T2%,%T3%,%T4%)
and TSX.StoryID = TS5.StoryID
)
and (SELECT Count(*)
From TopicStory TZ1
Where TZ1.TopicID = %T1%
and NOT EXISTS (SELECT *
From TopicStory TX1
Where TX1.StoryID = TZ1.StoryID
and TX1.TopicID in (%T2%,%T3%,%T4%,TS5.TopicID)
)
) > 1
and (SELECT Count(*)
From TopicStory TZ2
Where TZ2.TopicID = %T2%
and NOT EXISTS (SELECT *
From TopicStory TX2
Where TX2.StoryID = TZ2.StoryID
and TX2.TopicID in (%T1%,%T3%,%T4%,TS5.TopicID)
)
) > 1
and (SELECT Count(*)
From TopicStory TZ3
Where TZ3.TopicID = %T3%
and NOT EXISTS (SELECT *
From TopicStory TX3
Where TX3.StoryID = TZ3.StoryID
and TX3.TopicID in (%T1%,%T2%,%T4%,TS5.TopicID)
)
) > 1
and (SELECT Count(*)
From TopicStory TZ4
Where TZ4.TopicID = %T4%
and NOT EXISTS (SELECT *
From TopicStory TX3
Where TX3.StoryID = TZ3.StoryID
and TX3.TopicID in (%T1%,%T2%,%T3%,TS5.TopicID)
)
) > 1
Group By TS5.TopicID
Having Count(*) > 1
的功能集的MySQL是一個進展中的工作,所以可以想象在存儲過程中的高效 實現是可能的,其中光標可以採取主題列出的 作用。然而,如果 「遊標」是外部管理列表(例如PHP),並且數據庫查詢 保持儘可能簡單,我會對自己的良好業績充滿信心。
你想用什麼語言來完成? – CraigW 2011-06-15 21:13:40
這似乎是一個主題和故事之間的二分圖上的一種匹配問題。目標是找到一個解決方案還是列出所有可能的解決方案? – hardmath 2011-06-15 21:17:53
@CraigW:語言是PHP和MySQL。 – akanevsky 2011-06-15 21:18:28