n_queens problem n皇后问题之对角约束的实现

什么是n皇后问题详见:八皇后问题 - 维基百科,自由的百科全书 (wikipedia.org)

简言之:

在n*n的网格上,共有n个皇后,要求任两个不能在同一行或者同一列或对角的位置上,求共有多少种摆放方式或最多能放下多少个皇后

这篇笔记主要记录一下对角约束的实现:

(1)diagonal的用法示例

import numpy as np
x = np.arange(64).reshape(8,8)
print(x)
[[ 0  1  2  3  4  5  6  7]
 [ 8  9 10 11 12 13 14 15]
 [16 17 18 19 20 21 22 23]
 [24 25 26 27 28 29 30 31]
 [32 33 34 35 36 37 38 39]
 [40 41 42 43 44 45 46 47]
 [48 49 50 51 52 53 54 55]
 [56 57 58 59 60 61 62 63]]
print(x.diagonal(0))#输出主对角元素
[ 0  9 18 27 36 45 54 63]
print(x.diagonal(2))#输出偏移量为2的对角元素(以一个列表的形式)
[ 2 11 20 29 38 47]
print(x.diagonal(-2))#输出偏移量为-2的元素
[16 25 34 43 52 61]
x1=np.flipud(x)#按垂直方向翻转x
print(x1)
[[56 57 58 59 60 61 62 63]
 [48 49 50 51 52 53 54 55]
 [40 41 42 43 44 45 46 47]
 [32 33 34 35 36 37 38 39]
 [24 25 26 27 28 29 30 31]
 [16 17 18 19 20 21 22 23]
 [ 8  9 10 11 12 13 14 15]
 [ 0  1  2  3  4  5  6  7]]
x2=np.fliplr(x)#按水平方向翻转x
print(x2)
[[ 7  6  5  4  3  2  1  0]
 [15 14 13 12 11 10  9  8]
 [23 22 21 20 19 18 17 16]
 [31 30 29 28 27 26 25 24]
 [39 38 37 36 35 34 33 32]
 [47 46 45 44 43 42 41 40]
 [55 54 53 52 51 50 49 48]
 [63 62 61 60 59 58 57 56]]

(2)8皇后问题的实现

import numpy as np
import gurobipy as gp
from gurobipy import GRB

n = 8
# 创建模型
m = gp.Model("queen")

# 设置变量
x = m.addMVar((8,8), vtype = GRB.BINARY, name="x")

#设置目标函数
m.setObjective(x.sum(), GRB.MAXIMIZE)

#添加约束条件

#每行最多一个
m.addConstr(x.sum(axis=1) <=1, name="row")

#每列最多一个
m.addConstr(x.sum(axis=0) <= 1, name="col")

# 正对角线最多一个
for i in range(-n+1, n):
    m.addConstr(sum(x.diagonal(i)) <= 1, name="diagonal")

# 反对角线最多一个
#x1= np.fliplr(x) # 水平翻转
for i in range(-n+1, n):
     #m.addConstr(sum(x1.diagonal(i)) <= 1, name="anti-diagonal")
     m.addConstr(sum(x[:, ::-1].diagonal(i)) <= 1, name="anti-diagonal")
m.optimize()

print(x.X)
print(f"Queens placed :{m.ObjVal:.0f}")

注:因为fliplr操作的对象是数组numpy,所以不能直接对Gurobi变量进行fliplr操作,如会出现以下错误:

目前还没有找到GUROBI对矩阵变量进行翻转的python API(后续遇到了回来补充),  所以采用以下方式来进行翻转:

m.addConstr(sum(x[:, ::-1].diagonal(i)) <= 1, name="anti-diagonal")

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值