列出多个可行解
方法为定义一个回调接口供Solver使用,方便获取所有的解
# 定义一个类VarArraySolutionPrinter(大意为多可行解,官网命名), 类中命名方法:cp_model.CpSolverSolutionCallback
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
python使用类(class)来创建对象
class 类名(父类名:成员函数及成员变量),其中父类名可略,默认为object
父类名表示继承这个父类的属性
#定义函数:命名为self,有variables属性
def __init__(self, variables):
__init__表示类的对象被建立时,马上运行,对对象进行初始化。
在对类对象(class)进行实例化过程中,为防止缺少类中属性等情况发展,希望将类“封装”,解决方法为类内部定义一个def __init__(命名, 属性1,属性2)
函数,在执行实例化过程中预先设定好需要哪些属性,同时可以在输入class中不同实例时可以正确地初始化
相当于用先用一段注释占着__init__函数内的位置
定义__init__后,执行实例化的过程须变成命名(属性1, 属性2)
新建的实例包括其参数,传给__init__函数并初始化后,执行它。
def __init__(命名, 属性1,属性2)
语句中习惯上J将命名设为self。新建的实例传给self后,就可以在__init__函数内创建并初始化它的属性,一般呈现为 def __init__(self, 属性1,属性2)
cp_model.CpSolverSolutionCallback.__init__(self)#调用__init__(self)
self.__variables = variables #定义selfvariables等于求到的解
self.__solution_count = 1 #定义solution_count等于1,用于计数结构数
__前单下划线:保护变量,一般只能够被类对象和子类对象内部才能够访问到这些变量,一般情况下外部不得访问,
def on_solution_callback(self):
print('可行解第 %i 组' % self.__solution_count)
print('目标函数值 = %i' % self.ObjectiveValue())
for v in self.__variables: #遍历self.__variables
print(' %s = %i' % (v, self.Value(v)), end=' ')#end=' '不换行
print() #输出空一行
self.__solution_count += 1 #解的组数加1
def solution_count(self):#定义函数colution_count,用于组数
return self.__solution_count
return 返回值的重要性 定义了一个函数,建议都带一个返回值,不然无法进行赋值
#完整代码
#导入OR-Tools中的CP-SAT求解器中的cp_model模块
from ortools.sat.python import cp_model
# 定义一个回调接口供Solver使用,方便获取所有的解
# 定义一个类VarArraySolutionPrinter( 多可行解), 类中调用方法:cp_model.CpSolverSolutionCallback
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
def __init__(self, variables):#定义函数。命名为self,包含variables变量
cp_model.CpSolverSolutionCallback.__init__(self)
self.__variables = variables #定义self.__variables等于变量
self.__solution_count = 0#从1开始计数
def on_solution_callback(self):#定义函数callback,用于输出结果
print('可行解第 %i组' % self.__solution_count)
print('目标函数值 = %i' % self.ObjectiveValue())
for v in self.__variables:#遍历self.__variables,为输出变量各值
print(' %s = %i' % (v, self.Value(v)), end=' ')#end=' '表示不换行
print() #换行
self.__solution_count += 1
def solution_count(self):#定义函数colution_count,用于组数
return self.__solution_count #返回解的组数值
#以上官方文件略修改
def main():
# 实例化CP约束规划模型类
model = cp_model.CpModel()
# 创建变量,和线性规划一样,需要指定变量的取值范围
x1 = model.NewIntVar(0, 4, 'x1')
x2 = model.NewIntVar(0, 3, 'x2')
# 添加约束
model.Add(x1+ 3*x2 <=8)
# 添加目标函数
model.Maximize(2*x1 + 3* x2)
# 创建求解器并求解
solver = cp_model.CpSolver() #使用CpSolver求解
solution_printer = VarArraySolutionPrinter([x1, x2]) #按照前面 VarArraySolutionPrinter函数,打印出x1, x2,此时[x1, x2]已经赋值给了ariables
status = solver.SolveWithSolutionCallback(model, solution_printer)
# 打印结果
print('求解状态 = %s' % solver.StatusName(status))
#注意到的,在后面有一行是打印求解状态的solver.StatusName(status),关于求解器的结果有这么几种:
# OPTIMAL:找到了最优可行解
# FEASIBLE:找到了一个可行的解,但我们不知道它是否是最优解
# INFEASIBLE:这个问题被证明是不可行的
# MODEL_INVALID:给定的CpModelProto没有通过验证步骤,建议可以通过调用ValidateCpModel(model_proto)来获得详细的错误信息
# UNKNOWN:模型的状态是未知的,因为已经达到了搜索限制
print('可行解数量: %i' % solution_printer.solution_count())
main()