如何用约束变量统计整数列表中大于5的元素数量?代码问题解惑
整数规划约束问题:布尔求和与除法约束的异常原因
问题场景
给定整数列表(比如[1,2,5,3,8,10]),要通过变量统计列表里大于5的元素数量,再用这个变量做除法约束。但代码运行后,用变量s1(预期值为3)写的除法约束,和直接写3的结果不一样;把s1的定义域改成1-3后就正常了,搞不懂为啥。
用户代码
bs = [] for i in range(6): b = model.NewBoolVar(f'b_{i}') p = model.NewIntVar(s, 50, f'p_{i}') model.Add(p >= 5).OnlyEnforceIf(b) model.Add(p < 5).OnlyEnforceIf(b.Not()) bs.append(b) x = model.NewIntVar(0, 10000, 'x') y = model.NewIntVar(0, 10000, 'y') s1 = model.NewIntVar(0, 3, 's1') #... model.Add(s1 == sum(bs)) model.AddDivisionEquality(x, y, s1)
原因分析
1. 除数为0的潜在冲突
OR-Tools里的AddDivisionEquality(x, y, s1)本质是要求y = x * s1(也就是y必须能被s1整除,x是商)。当你把s1的下界设为0时,求解器必须考虑s1=0的情况:
- 数学上除数不能为0,这会导致约束逻辑出现矛盾,求解器可能会优先寻找满足
s1=0的解(此时要求y=0),直接忽略了你预期的s1=3的场景,最终结果自然和直接写3不一样。
2. 布尔约束的小细节(额外提醒)
你代码里的布尔变量约束是p>=5时b=True,这会把列表里的5也统计进去,所以s1预期为3(对应5、8、10三个元素)。如果你的需求是严格大于5,得把约束改成:
model.Add(p > 5).OnlyEnforceIf(b) model.Add(p <= 5).OnlyEnforceIf(b.Not())
这样5就不会被计入统计了。
3. 为什么改定义域就正常了
把s1的定义域改成1-3,直接排除了s1=0的非法情况,求解器只能在1、2、3里找符合s1 == sum(bs)的值,最终匹配到s1=3,除法约束的逻辑就和直接写3完全一致了。
总结
核心问题就是初始代码允许s1=0,触发了除法约束的非法场景,干扰了求解器的计算。把s1下界设为1,排除除数为0的可能,就能得到预期结果。
内容的提问来源于stack exchange,提问作者John M.
相关产品推荐
相关产品推荐

