我對搜索算法和回溯編程頗感興趣。現在,我已經實現了算法X(請參閱我的其他帖子:Determine conflict-free sets?)來解決精確的覆蓋問題。這工作得很好,但我現在有興趣用一個更基本的回溯方法來解決這個問題。我無法弄清楚如何做到這一點。問題描述與以前相同:使用啓發式實現回溯搜索?
假設您有一堆集合,而每個集合都有幾個子集。
SET1 = {(香蕉,菠蘿,橙),(蘋果,羽衣甘藍,黃瓜),(洋蔥,大蒜)}
SET2 = {(香蕉,黃瓜,大蒜),(鱷梨,番茄)}
...
SETN = {...}
現在的目標是選擇來自每個組的一個子集,而每一子集必須無衝突與任何其他選擇的子集(一種元素是不包含在任何其他選擇的子集中)。
作爲一個例子,我寫了兩個Java類。這些集合由單個字符標識,元素是純數字。
我專門有兩個問題:
- 如何遍歷所有集合/以這樣的方式,使用啓發式是可能的子集(選擇以最小的元素,最低的成本集,...)
- 如何維護選定的集合+子集及其包含的元素。
我可以找到的所有其他示例是Sudoku或n-Queens,都使用固定for循環。除此之外,我正在考慮一個相當普遍的方法,如果一個選定的路徑/集合可能與先前選擇的子集/元素髮生衝突,那麼函數「isPossiblePartialSolution」可能用於檢查。
這裏有兩個Java類:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Set> allSets = buildRandomTest();
for(Set r : allSets) {
System.out.print("Set with id: " + r.id + " is subset in collection: " + r.name + " and contains: ");
for(Integer n : r.listOfElements) {
System.out.print(" " + n + " ");
}
System.out.println();
}
}
public static int myRandomRange(int low, int high) {
return (int) (Math.random() * (++high - low) + low);
}
public static ArrayList<Set> buildRandomTest() {
ArrayList<Set> mySet = new ArrayList<Set>();
int numberOfSets = myRandomRange(10, 12);
for(int i=0; i<numberOfSets; i++) {
String nameOfSet = Character.toString((char) myRandomRange(65, 67));
Set tmp = new Set(nameOfSet, i);
ArrayList<Integer> listOfElements = new ArrayList<Integer>();
int elementsInList = myRandomRange(2, 4);
for(int j=0; j<elementsInList; j++) {
listOfElements.add(myRandomRange(1,30));
}
tmp.listOfElements = listOfElements;
mySet.add(tmp);
}
return mySet;
}
}
和
import java.util.ArrayList;
public class Set {
public String name;
public int id;
public ArrayList<Integer> listOfElements;
public Set(String name, int id) {
this.name = name;
this.id = id;
listOfElements = new ArrayList<Integer>();
}
}
回溯的想法是相當普遍的,可以應用於許多問題。跳舞鏈接只能用於確切的封面問題。應該可以使用'正常'回溯方法來實現這一點(我知道,與DLX相比,這將會變慢)。根據我的理解,我們需要一個功能,然後告訴我們是否存在與以前的任何決策衝突。除此之外,這允許使用不同的啓發式! – user26372 2013-05-13 09:04:01
使用不同的啓發式是我試圖實現的。就形象而言,「購買」一套或另一套便宜(與Dancing Links不同,我們會以最小的成本選擇套餐,而不是最低的套餐)。這不能使用跳舞鏈接完成。 – user26372 2013-05-13 09:08:24
@ user26372跳舞鏈接*通常*使用啓發式「首先檢查最少1的列」(即嘗試首先滿足最困難約束的行),但是如果不嘗試使用不同的啓發式,那樣的一個。請參閱[我自己在C中的Dancing Links實現](http://www.club.cc.cmu.edu/~ajo/free-software/snippets/dance.c),並想象如何更改下面的代碼'#if USE_HEURISTIC'使用不同的啓發式。 – Quuxplusone 2013-05-13 17:40:14