我正在尝试解决最小的图形着色问题。我正在尝试使用cvxpy将其解决为mip。我正在遵循此网址中描述的解决方案的概述:
https://manas.tech/blog/2010/09/16/modelling-graph-coloring-with-integer-linear-programming.html
我不确定我是否了解如何正确创建cvxpy变量以及如何定义约束。下面有示例输入数据,以及创建变量,约束和目标函数,解决问题和返回解决方案的代码。
我认为此输入的正确答案应该是:
‘2 1\n0 1 0 0’
这是要求的最小颜色数为2,除节点1外,所有节点都为相同颜色。
我正在创建w变量以计算所用颜色的数量:
w = cvxpy.Variable(j, boolean=True)
我想我正在做的是创建一个长度等于节点数的二进制变量。这样的想法是,您可以使用的最大颜色数将等于节点数。所以最大颜色:
w=[1,1,1,1]
我将w描绘成一个二进制变量,例如一个列表,其中的值可以是0或1,表示该颜色是否被任何节点使用。
然后创建目标函数:
obj=cvxpy.sum(w,axis=0)
我想我正在对行中的条目求和,因此,例如:
w=[1,1,0,0]
obj=2
我还创建了一个变量x来指示给定节点的颜色:
x = cvxpy.Variable((j,int(first_line[0])), boolean=True)
我将其描述为带有二进制值的二维数组,其中列表示节点,行表示颜色。
因此,例如,如果节点0的颜色为0,节点1的颜色为1,节点2的颜色为2,节点3的颜色为2,我可以想象x看起来像:
[[1,0,0,0],[0,1,0,0],[0,0,1,1],[0,0,0,0]]
有人可以告诉我我是否正确理解并正确创建了选择变量?我也理解并正确创建了目标函数吗?这就是我描述目标函数的方式是否与我创建目标函数的方式相匹配?并感谢您对我定义的其他约束或代码的任何输入。我正在学习线性编程,并且试图理解cvxpy语法。
样本数据:
input_data
'4 3\n0 1\n1 2\n1 3\n'
# parse the input
lines = input_data.split('\n')
first_line = lines[0].split()
node_count = int(first_line[0])
edge_count = int(first_line[1])
edges = []
for i in range(1, edge_count + 1):
line = lines[i]
parts = line.split()
edges.append((int(parts[0]), int(parts[1])))
edges
# Output:
[(0, 1), (1, 2), (1, 3)]
# solution using cvxpy solver
import numpy as np
import cvxpy
from collections import namedtuple
# selection variables
# binary variable if at least one node is color j
j=int(first_line[0])
# w=1 if at least one node has color j
w = cvxpy.Variable(j, boolean=True)
# x=1 if node i is color j
x = cvxpy.Variable((j,int(first_line[0])), boolean=True)
# Objective function
# minimize number of colors needed
obj=cvxpy.sum(w,axis=0)
# constraints
# 1 color per node
node_color=cvxpy.sum(x,axis=1)==1
# for adjacent nodes at most 1 node has color
diff_col = []
for edge in edges:
for k in range(node_count):
diff_col += [
# x[edge[0],k]+x[edge[1],k]<=1
x[k,edge[0]]+x[k,edge[1]]<=1
]
# w is upper bound for color of node x<=w
upper_bound = []
for i in range(j):
for k in range(j):
upper_bound += [
x[k,i]<=w[i]
]
# constraints
constraints=[node_color]+diff_col+upper_bound
# solving problem
# cvxpy must be passed as a list
graph_problem = cvxpy.Problem(cvxpy.Minimize(obj), constraints)
# Solving the problem
graph_problem.solve(solver=cvxpy.GLPK_MI)
value2=int(graph_problem.solve(solver=cvxpy.GLPK_MI))
# taken2=[int(i) for i in selection.value.tolist()]
# taken2=[int(i) for i in w.value.tolist()]
taken2=[int(i) for i in w.value.tolist()]
# prepare the solution in the specified output format
output_data2 = str(value2) + ' ' + str(0) + '\n'
output_data2 += ' '.join(map(str, taken2))
output_data2
'1 0\n0 0 0 1'
答案 0 :(得分:0)
您的解决方案几乎是正确的。这里的主要问题是变量x的定义。根据博客文章
x_ {ij}变量,当且仅当节点i被分配了颜色j时才会为真
表示x的大小为(节点nb,颜色nb)。
在您的代码中,您需要将x更改为:
x = cvxpy.Variable((node_count, j), boolean=True)
,然后是第二和第三个约束:
# for adjacent nodes at most 1 node has color
diff_col = []
for edge in edges:
for k in range(j):
diff_col += [
x[edge[0],k]+x[edge[1],k]<=1
]
# w is upper bound for color of node x<=w
upper_bound = []
for i in range(node_count):
for k in range(j):
upper_bound += [
x[i,k]<=w[k]
]
然后输出是预期的,即使用2种颜色:节点1的一种颜色和节点0、2、3的另一种颜色(因为它们不相邻)。