一、题目
在N×N的国际象棋棋盘上放置N个皇后,让其中任何一个皇后都无法直接吃掉其他的皇后。为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。
二、分析
以往求解n皇后问题基本都是回溯法、最小冲突法以及各种智能优化算法。但在数学建模这门课上,我们考虑用线性规划的方法进行求解。n皇后问题的重点在于任意一个皇后互相不能攻击,因此我们可以得出一下推论:
(1)每一行一列只允许放置一个皇后。
(2)每一条与主对角线或副对角线平行的一组元素最多只允许放置一个皇后.
根据以上的分析,这里以4皇后为例,我们可以容易的列出以下方程与约束条件:
上面就是约束条件了,两个等式约束,还有右边一坨的不等式约束,这就是求解的关键。
三、matlab代码(以4皇后为例子)
这里要用到matlab里面的一个函数:intlinprog,等下会讲。
首先把4皇后问题矩阵出来:
声明一个f ,也就是x1+x2+.....+x16的系数矩阵
%n皇后问题,以4皇后为例
f = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1];
以右边的不等式约束条件,声明b保存右边的系数
A即为左边变量的系数矩阵。
就是那张图中右边的不等式约束,A是系数矩阵,b是右边那列1。
b = [1;1;1;1;1;1;1;1;1;1];
A=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1;0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0;
0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0; 0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0;
0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0; 0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0;
0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0; 0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0;
0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0; 0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0];
同理,根据行和列约束,列出相应的等式约束Aeq ,beq,AeqX = beq
Aeq = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1;
1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0;
0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0;
0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0;
0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1;
1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0;
0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0;
0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0;
0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1];
beq = [4;1;1;1;1;1;1;1;1];
我以第一行为例解释一下:第一行就是x1到x16的系数(比如x1-x4是第一行),他们全部相加得到4,也就是说整个棋盘只能放4个皇后。
比如x2能放了皇后,那么x1,x3,x4,还有x2下面的都放不了(约束)。
-
设置每个元素都是整数,并且确定元素的上界为1,下界为0。简单的说,就是每个元素的值只能是1或者是0;
调用matlab的intlinprog函数进行线性规划求解,结果保存在x中。
如果调用不了此函数,说明你matlab装的时候少钩了很多东西,我是全部选上了。。
lb是下界,也就是0。ub是上界,也就是1。因为不放皇后的地方自然标记0,放皇后的地方要标记1。总不能你不放皇后,反而还给人家标个负1w吧。
1、intlinprog,第一个参数是-f,至于为什么是负的,我忘了。
2、intcon忘了。A,b,就是不等式约束,Aeq,beq就是等式的约束。
求解的结果保存在tem中,disp调用一下就能看到结果了。
intcon=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16];
lb = zeros(16,1);%设置6个变量的下届
ub = ones(16,1); %设置6个变量的上界
%计算
[x,fval] = intlinprog(-f,intcon,A,b,Aeq,beq,lb,ub);
tem=[0,0,0,0;0,0,0,0;0,0,0,0;0,0,0,0];
m = 1;
for i = 1:4
for j = 1:4
tem(i,j) = x(m);
m = m + 1;
end
end
disp(tem);
四、结果
嗯,解出来了。那么n维是同理的。
五、组合拍卖问题
都是一样的。
以题目为例,有6个顾客,第一个顾客想要标号1的商品,并且出价为6。我们将bid_items里的元素视为变量X1-X6。
很明显,我们要求的是一个最大值:
max(6X1 + 3X2 + 12X3 + 12X4 + 8X5 + 16X6)
我下面给出了约束条件:
然后直接上代码了,结束!
bidValues = [6;3;12;12;8;16];
%不等式右边的值
%x1 + 2x2 + 7x3 + 4x4 + 6x5 + 8x6 <= 10,原理是1234号商品,加起来刚好10,不能卖超过
%但也可能出现卖了10个1的情况,我们下面继续对其进行约束
%首先,x1 和 x4不能同时出现,因为x1组和x4组都有商品1!!!
%所以,其他的同理,由此得到全部约束
b = [10;1;1;1;1;1;1];
A = [1,2,7,4,6,8;1,0,0,1,0,0; 1,0,0,0,0,1; 0,1,0,0,1,0; 0,0,1,1,0,0; 0,0,1,0,0,1; 0,0,0,1,0,1];
%设置整形
intcon=[1 2 3 4 5 6];
lb = zeros(6,1);%设置6个变量的下届
ub=ones(6,1); %设置6个变量的上界
%计算
[x,fval] = intlinprog(-bidValues,intcon,A,b,[],[],lb,ub);
%注意,我们求的是最大值,这里需要取反
y = -fval;
%打印每个变量的取值信息
disp(x);
%打印最后答案
disp(y);
结果如下:
意思是选择卖出[1]、[2]、[3, 4]得到的收益最大。