用z3py寻找集合中的最小元素数。

问题描述 投票:0回答:2

练习:求集合Z中元素加起来的最小数目为4285.其中 Z = { w(i): w(n) - n^2 - n + 1, i = 1,2,...,30 }

我创造了一个解决方案。

def f(t):
    return t ** 2 - t + 1


opt = z3.Optimize()

x = IntVector('x', 30)
x_val = [And(x[i] >= 0, x[i] <= 1) for i in range(30)]
opt.add(x_val)

m = [x[i] * f(i + 1) for i in range(30)]
m_sum = z3.Sum(m)

opt.add(m_sum == 4285)
opt.minimize(z3.Sum(x))

if z3.sat == opt.check():
    model = opt.model()
    print(model)

但效果太慢 只对小数有效。我怎样才能改进它呢?

python z3 solver smt z3py
2个回答
3
投票

在z3中用整数来表示布尔值几乎总是一个坏主意。所以,与其使用一个整数向量,在那里你说项目在0-1之间,不如简单地使用布尔向量和 If 构建。就像这样。

from z3 import *

def f(t):
    return t ** 2 - t + 1

opt = z3.Optimize()

x = BoolVector('x', 30)

m = [If(x[i], f(i + 1), 0) for i in range(30)]
m_sum = z3.Sum(m)

opt.add(m_sum == 4285)

opt.minimize(z3.Sum([If(x[i], 1, 0) for i in range(30)]))

if z3.sat == opt.check():
    model = opt.model()
    print(model)

当我运行这个的时候,它很快就找到了解决方案。 When I run this, it goes really quickly and finds the solution:

[x__0 = False,
 x__1 = False,
 x__2 = False,
 x__3 = False,
 x__4 = False,
 x__5 = False,
 x__6 = False,
 x__7 = False,
 x__8 = False,
 x__9 = False,
 x__10 = False,
 x__11 = False,
 x__12 = False,
 x__13 = True,
 x__14 = False,
 x__15 = False,
 x__16 = False,
 x__17 = True,
 x__18 = False,
 x__19 = False,
 x__20 = False,
 x__21 = False,
 x__22 = False,
 x__23 = False,
 x__24 = False,
 x__25 = True,
 x__26 = True,
 x__27 = True,
 x__28 = True,
 x__29 = True]

我没有检查这是否是正确的解决方案, 但至少它应该让你开始!


1
投票

不是答案,而是确认了7位的 解决办法 提议 别名.

我尝试了以下MiniZinc模型。

int: n = 30;
set of int: N = 1..n;

function int: f(int: t) =
  t*t - t + 1;

array[N] of var bool: x;

constraint ( 4285 == sum([x[i] * f(i) | i in N]) );

var int: bitCount = sum([ x[i] | i in N]);

solve minimize bitCount;

output ["#\(bitCount): "] ++
       ["\(if x[i] then 1 else 0 endif)" | i in N];

结果:

#7: 000000000000000010001001011011
© www.soinside.com 2019 - 2024. All rights reserved.