use*_*372 7 java search backtracking np
我对搜索算法和回溯编程非常感兴趣.现在,我已经实现了算法X(请参阅我的其他帖子:确定无冲突集?)来解决确切的覆盖问题.这非常有效但我现在有兴趣用更基本的回溯变体来解决这个问题.我无法弄清楚如何做到这一点.问题描述与以前相同:
假设你有一堆集合,而每个集合都有几个子集.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
和
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>();
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:实际上,听起来您已经实现了 Dancing Links(使用名称“算法 X”),所以我不确定您要什么。“回溯的更基本变体”是指“较慢的变体”吗?跳舞链接是你能得到的最基础的......
原始答案:如果我这样做,我会尝试将其简化为精确覆盖问题,这可以通过Dancing Links来解决。即,构造一个由 0 和 1 组成的矩阵,找到其行的子集,使得每列中恰好有一个 1,然后将该行集转换回原始问题的答案。
以下答案是用 C++(11) 编写的,但希望您能看到如何将其转换为 Java。用 Java 实现 Dancing Links 留给读者和/或您选择的搜索引擎作为练习。
enum Element {
apple, avocado, banana, cucumber, garlic,
kale, onion, orange, pineapple, NUM_ELEMENTS
};
std::vector<std::vector<std::set<Element>>> sets = {
{ {banana, pineapple, orange}, {apple, kale, cucumber}, {onion, garlic} },
{ {banana, cucumber, garlic}, {avocado, tomato} },
...
};
int rows, columns;
// One row per subset, obviously...
rows = 0;
for (auto &vs : sets) {
rows += vs.size();
}
// ...plus N more rows for "vegetable X is not in any selected subset".
rows += NUM_ELEMENTS;
// One column per vegetable, obviously...
columns = NUM_ELEMENTS;
// ...plus N more columns for "we've chosen a subset from set X".
columns += sets.size();
Matrix M(rows, columns);
M.initialize_to_all_zeros();
int r = 0;
for (int i=0; i < sets.size(); ++i) {
for (int j=0; j < sets[i].size(); ++j) {
auto &subset = sets[i][j];
M[r][NUM_ELEMENTS + i] = 1; // the subset is a member of set i
for (Element veg : subset) {
M[r][veg] = 1; // the subset contains this element
}
++r;
}
}
for (Element veg = apple; veg < NUM_ELEMENTS; ++veg) {
M[r][veg] = 1;
++r;
}
// Now perform Dancing Links on the matrix to compute an exact cover.
std::set<int> row_indices = dancing_links(M);
// Now print out the subsets.
r = 0;
for (int i=0; i < sets.size(); ++i) {
for (int j=0; j < sets[i].size(); ++j) {
if (row_indices.find(r) != row_indices.end()) {
print_set(sets[i][j]);
}
++r;
}
}
// And print the unused vegetables, just for kicks.
for (Element veg = apple; veg < NUM_ELEMENTS; ++veg) {
if (row_indices.find(r) != row_indices.end()) {
std::cout << "Vegetable " << veg << " was not mentioned above.\n";
}
++r;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1897 次 |
| 最近记录: |