目录
前言
一 钻井布局问题
第一问分析
第二问分析
总结
前言
这里讲述99年的钻井布局问题,利用这个问题讲述模型优化,LINGO,MATLAB的使用
一 钻井布局问题
这个是钻井布局的原题,坐标的位置为
a = [0.50,1.41,3.00,3.37,3.40,4.72,4.72,5.43,7.57,8.38,8.98,9.50];
b = [2.00,3.50,1.50,3.51,5.50,2.00,6.24,4.10,2.01,4.50,3.41,0.80];
这个a是每一个井的横坐标,b是每一个井的纵坐标
第一问分析
题意:我们要去移动网格,然后这个井的x坐标和y坐标距离这个网格的点的x坐标和y坐标的的误差可以再0.05之内,这个是十分重要的
我们先用MATLAB把这个图画出来
代码如下a=[0.50,1.41,3.00,3.37,3.40,4.72,4.72,5.43,7.57,8.38,8.98,9.50]; b=[2.00,3.50,1.50,3.51,5.50,2.00,6.24,4.10,2.01,4.50,3.41,0.80]; plot(a,b,'o');//画点 grid; //显示表格 for i = 1:12 text(a(i)+0.1,b(i),int2str(i));//显示坐标点的标记 end
然后我们要去根据题意知道这个模型要怎么进行构建
模型就是我们0---1变量规划,算法中就是背包问题,选择还是不选择,选择是1,不选择是0,然后只要把这些值加起来就好了,因为我们就最多就是12口井,那全部取1的话,那不就是12吗,向下很多人都听懂这个了
我们可以进行总结一下,这个就是选择和不选择的问题
所以我们有一个变量肯定是要记录0和1的,那么我们就找到了一个变量了,在创建模型中,变量是十分关键的,现在我们创建了一个变量就是0,1的f
然后剩下变量不就是我们上面的x坐标和y坐标嘛
然后还有一个就是我们平移,平移多少呢?我们不知道,所以设一个x和y,因为x和y都要移动嘛
现在我们就有5个变量了
这个是我们建立的第一个模型
我们可以看到这个就是利用了水井坐标减去方格坐标的绝对值小于0.05,为什么呢?读者自己思考,因为这个很关键,讲出来的话就没意义了
然后f就是我们所说的01变量,但是这个模型好像编写不出来,为什么?
因为我们的式子要和01变量进行有所关联,所以我们直接这样就好了
然后我们就得到了关联,这个时候我们可以先用LINGO进行编写或者MATLAB编写
LINGOsets: aa/1..12/:s,b,f; endsets data: s = 0.50,1.41,3.00,3.37,3.40,4.72,4.72,5.43,7.57,8.38,8.98,5.50; b = 2.00,3.50,1.50,3.51,5.50,2.00,6.24,4.10,2.01,4.50,3.41,0.80; enddata Max = @sum(aa(i):f(i)); x<1; x>0; y<1; y>0; @for(aa(i):@abs(s(i)+x-@floor(s(i)+x+0.5))*f(i)<=0.05); @for(aa(i):@abs(b(i)+y-@floor(b(i)+y+0.5))*f(i)<=0.05); @for(aa(i):@bin(f(i)));
这里讲解一下语法,可能很多读者不着调这个语法
首先这个sets是创建集合的,endset是结束创建集合,这里你可以理解一个数组,sdf是aa的元素,然后这个sfd里面都有12个元素,这个元素你可以自己进行赋值,如果只有一个的话,那就直接向我写x和y一样就好了
然后这个data是进行赋值的区域enddata是结束赋值的语句,这是一一对应的
然后后面就是for循环,这个for循环前面aa你可以想象成for循环的里面的三个表达式,aa就是位置,然后循环12次
MATLABa=[0.50,1.41,3.00,3.37,3.40,4.72,4.72,5.43,7.57,8.38,8.98,9.50]; b=[2.00,3.50,1.50,3.51,5.50,2.00,6.24,4.10,2.01,4.50,3.41,0.80]; m = 0; d = 0; c=[]; e=[]; for x=0:0.01:1 aa = a + x; for y=0:0.01:1 bb = b + y; n = 0; for i = 1:12 if abs(aa(i) - round(aa(i))) <= 0.05 && abs(bb(i) - round(bb(i))) <= 0.05 n = n + 1; c(end + 1) = i; end end if m < n m = n; e = c; end c = []; end end
这个m的值就是我们的答案,这个MATLAB跟我们c差不多,这里就不多介绍了,很简单
第二问分析
第二问就是在第一问的基础上加了一个旋转
那我们是先旋转还是先平移呢?
其实都可以,我这里选择的是先旋转,读者可以自行思考另外一个情况
我们要知道我们已经知道了这个点的坐标,那么我们就要把他基于原点的角度知道,这里使用arctan就好了,可以直接求取角度,在原有的角度上进行增加角度,然后转动的只后把这个x和y计算出来,在井的坐标上加上就好了,这个就是旋转,平移更上述的一样
首先我们先要利用MATLAB来进行变成才好理解构建模型a = [0.50,1.41,3.00,3.37,3.40,4.72,4.72,5.43,7.57,8.38,8.98,9.50]; b = [2.00,3.50,1.50,3.51,5.50,2.00,6.24,4.10,2.01,4.50,3.41,0.80]; max = 0; rr = atan(b./a); long = sqrt(a.^2 + b.^2); for ang = 0:0.01:pi*2 for x = 0:0.01:1 for y = 0:0.01:1 m = 0; for i = 1:12 xx = long(i) * cos(rr(i) + ang); yy = long(i) * sin(rr(i) + ang); aa = xx + x; bb = yy + y; if sqrt((aa - round(aa))^2 + (bb - round(bb))^2) <= 0.05 m = m + 1; end end if max < m max = m; end end end end
我们利用原长来计算这个转动的x和y然后再加上平移就好了,注意这里的是计算欧里距离,别弄错了,如果这个理解了之后就可以进行模型的搭建了,这里是作者自己构建的,每个模型都是不一样,但是意思正确即可
这个是作者自己构建的,有了这个模型我们就可以再LINGO上面敲出来了
sets: aa/1..12/:a,b,f,p,ang1,ang2,liang1,liang2,c; endsets data: a = 0.50,1.41,3.00,3.37,3.40,4.72,4.72,5.43,7.57,8.38,8.98,9.50; b = 2.00,3.50,1.50,3.51,5.50,2.00,6.24,4.10,2.01,4.50,3.41,0.80; enddata calc: @for(aa(i):c(i)=@atan(b(i)/a(i))); @for(aa(i):p(i)=@sqrt(a(i)^2 + b(i)^2)); endcalc max = @sum(aa(i):f(i)); @for(aa(i):@bin(f(i))); x<1; y<1; w<3.14/2; @for(aa(i):ang1(i)=@cos(c(i)+w)); @for(aa(i):ang2(i)=@sin(c(i)+w)); !@for(aa(i):liang1(i)=p(i)*ang1(i)); !@for(aa(i):liang2(i)=p(i)*ang2(i)); !@for(aa(i):@free(liang1(i))); !@for(aa(i):@free(liang2(i))); @for(aa(i):@free(ang1(i))); @for(aa(i):@free(ang2(i))); @for(aa(i):@sqrt((p(i)*ang1(i) + x -@floor(p(i)*ang1(i) + x + 0.5))^2 + (p(i)*ang2(i) + y-@floor(p(i)*ang2(i) + y + 0.5))^2)*f(i)<=0.05);
由于我们的编程的刚开始的算法很慢,然后作者就加了注释不断地优化,这里calc是数值区域,其他就是条件区域,这里要知道才可以进行算法地优化
最后地答案是6
然后这里要设置自由变量,因为lINGO是他这个角度地cos和sin如果取到了负值就默认正值,所以要设置为自由变量
总结
这里主要是非线性规划,怎么看出来的,因为乘以了未知量,模型地构建就是要抓住变量和约束条件,然后还理解了LINGO和MATLAB这两个工具地好处和编写