我在S的子集上有一个集合S和一个布尔值函数f。函数f具有“遗传属性”:如果f(A)为真且B是A的子集,则f(B)是的。
是否有算法可以找到S的最大子集,其中f的计算结果为真?在f(A)为真的意义上,集合A是最大的,但如果B包含A并且大于A,则f(B)为假。
答案 0 :(得分:1)
使用回溯。伪代码:
def A(c,r,u):
# c - current set
# r - remaining elements
# u - unused, forbidden elements
if r == []:
for i in u:
if f(c + [i]): # Check if c is really maximal
return
print c
else:
x = r[0]
r' = r without first element
if f(c + [x]):
A(c + [x], r', u)
A(c, r', u + [x])
运行A([],[a_1,a_2,...,a_n],[])
这具有指数复杂性,你无法避免它,例如,如果f(A)= A A最多有n / 2个元素,则指数多个最大集合。你需要更多地考虑f以获得更好的算法。
答案 1 :(得分:0)
遗传属性可以让您对搜索空间进行很好的修剪。如果元素已经存在,则对元素创建排序。然后,只创建具有已排序元素的集合。
从单元素集开始 - 找到满足......(1)
的集合然后创建所有两个元素集 - 对于每个元素集,尝试追加(1)中更大的所有集合...(2)重要:记住它们的关系:for sets {s}和{b}( s< b)from(1)如果{s,b}在(2)中,请记住{s,b} .tail为{b}并将{s,b}添加到集合{s} .offspring。
现在只需要增加元素数量。叫(2)“旧”并开始创建“新”。对于旧的每个s,尝试在s.tail.offspring中追加每个t,用另外一个元素形成集合。如果满足,则将其添加到“new”,将其.tail(设置为t)设置为s.offspring。因此,您将获得所有令人满意的3元素。 (为了优化你现在可以忘记来自“old”的所有.tails并让gc摆脱上一代)重复从3元素中获取4个元素等。
最大集是那些在s时不成功的集,也是空的.offspring。
答案 2 :(得分:0)
评估f意味着测试CNF公式的可满足性。我倾向于将搜索最大集合与SAT求解器集成。
从DPLL基础开始,进行以下修改。
除 true 或 false 外,还可以删除变量。当DPLL选择要分支的变量时,分支会有三种方式。
单位传播是相同的。
纯文字消除现在不起作用。但是,我们可以对纯变量(有用的真值或删除)进行双向分支,而不是三向分支。
逐步检查对于每个已分配的变量,是否只有该分配满足的子句。如果没有,修剪 - 这个子树不包含最大解。
如果部分赋值满足所有子句,则将已删除和未分配的变量集添加到输出中。可能有重复。