您的位置:首页 > 其它

数学建模中的整数规划总结及姜启源第4章(1-3)的解析

2016-04-22 01:04 471 查看
首先推荐一篇不错的博客点击打开链接

有关线性规划和非线性规划的实数解解法在前一篇文章有过详细的介绍点击打开链接

而现在引入的是整数规划问题,这里整数指的就是解向量有一个或多个要为整数,实际问题中无法切割的物品,比如人,电脑,手机,都是属于这类范畴~~

这里提供一个比较新的、专用于求解整数规划和0-1整数规划的函数——intlinprog

[x,fval,exitflag]= intlinprog(f,intcon,A,b,Aeq,beq,lb,ub)

这里intcon是哪些解要求为整数解

A,b就还是AX<b的向量

Aeq和beq是Aeq*x=beq的向量

lb是下限

bu是上限

比如



>> f=[-1,-1];
>> a=[1,2];
>> b=[-4 2;4 2;0 -2];
>> c=[-1;11;-1];
>> [x,fval]=intlinprog(f,a,b,c,[],[],zeros(2,1),[])


结果

x =

2
1

fval =

-3


如果是0 -1规划呢,也就是说解只能取0和1,那么我们上下限分别为0和1的向量即可.



>> f=[7,5,9,6,3];
>> a=[56 20 54 42 15;1 4 1 0 0;-1 -2 0 -1 -2];
>> b=[100;4;-2];
>> c=[1,2,3,4,5];%表示1,2,3,4,5都是整数解
>> [x,fval]=intlinprog(f,c,a,b,[],[],zeros(5,1),ones(5,1))%zeros就是代表5个数下界为0,ones表示5个数上界为1


结果:

x =

0
0
0
0
1

fval =

3


比如《matlab在数学建模中的应用》这本书中例2-11是用的暴力穷举,我们用intlinprog试一下

题目:

maxz=3x1-2x2+5x3

x1+2x2-x3<=2

x1+4x2+x3<=4

x1+x2<=3

4x2+x3<=6

x1,x2,x3=0或者1

>> f=[-3,2,-5];%这里注意因为是求最大值所以是相反数
>> a=[1 2 -1;1 4 1;1 1 0;0 4 1];
>> b=[2;4;3;6];
>> c=[1,2,3];
>> [x,fval]=intlinprog(f,c,a,b,[],[],zeros(3,1),ones(3,1))


结果:

x =

1
0
1

fval =

-8


当然了fval要取相反数(因为max嘛),结果与书上一致.

上面都是线性规划的整数规划(约束条件和目标函数都是1次),那么非线性规划的整数规划该如何求解呢?

随机大法好23333,果断上遗传算法

比如《matlab在数学建模中的应用》用matlab跑出的结果为47789,而c++实现的遗传算法可以得到更优解(当然更多时候是更差了,随机类的算法本就是有运气成分的),遗传算法的原理就不多说了,什么遗传算法解决tsp问题

,遗传算法解决背包问题有很多~~

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <cmath>
#define N  5//变量个数
#define num 100//种群大小
#define MAX 10000//最大迭代次数
#define pm 0.15//变异概率
#define pc 0.8//交配概率
#define M 10//罚函数的值
using namespace std;
typedef struct node
{
int f
;
int adapt;
}node;
node group[num],grouptemp[num];
int sumdistance;
int cmp(node a,node b)
{
return a.adapt>b.adapt;
}
int check(int i)//查看是否符合
{
if (group[i].f[0]+group[i].f[1]+group[i].f[2]+group[i].f[3]+group[i].f[4]>400)
return 0;
if (group[i].f[0]+2*group[i].f[1]+2*group[i].f[2]+group[i].f[3]+6*group[i].f[4]>800)
return 0;
if (2*group[i].f[0]+group[i].f[1]+6*group[i].f[2]>200)
return 0;
if (group[i].f[2]+group[i].f[3]+5*group[i].f[4]>200)
return 0;
return 1;
}
void initgroup()
{
int i,j;
srand(time(NULL));
for (i=0;i<num;i++)
{
for (j=0;j<N;j++)
group[i].f[j]=rand()%100;//随机0~99的数
if (!check(i))//如果不符合重新生成
i--;
}
printf("初始种群\n");
for (i=0;i<num;i++)
{
for (j=0;j<N;j++)
printf("%4d",group[i].f[j]);
printf("\n");
}

}
void evalute()
{
int i;
sumdistance=0;
for (i=0;i<num;i++)
{
group[i].adapt=group[i].f[0]*group[i].f[0]+group[i].f[1]*group[i].f[1]+3*group[i].f[2]*group[i].f[2]+4*group[i].f[3]*group[i].f[3]+2*group[i].f[4]*group[i].f[4]
-8*group[i].f[0]-2*group[i].f[1]-3*group[i].f[2]-group[i].f[3]-2*group[i].f[4];//评估函数
if (!check(i))//如果存在不可行解(这里是不可能出现负解的,如果有些题目出现+上最小值即可)
if (group[i].adapt>0)
group[i].adapt=group[i].adapt-M*group[i].adapt;
if (group[i].adapt>0)
sumdistance+=group[i].adapt;
}
sort(group,group+num,cmp);
}
void choose()
{
int i,j,t,temp;
int gradient[num];
int xuan[num];
gradient[1]=group[1].adapt;
for (i=1;i<num;i++)
{
if (group[i].adapt>0)
gradient[i]=gradient[i-1]+group[i].adapt;
else
gradient[i]=-1;
}
srand(time(NULL));
for (i=1;i<num;i++)
{
t=rand()%(sumdistance+1);//随机0~sumdistance的数
for (j=1;j<num;j++)
if (gradient[j]>=t)
{
xuan[i]=j;
break;
}
}
for (i=1;i<num;i++)
{
grouptemp[i].adapt=group[i].adapt;
for (j=0;j<N;j++)
grouptemp[i].f[j]=group[i].f[j];
}
for (i=1;i<num;i++)
{
temp=xuan[i];
group[i].adapt=grouptemp[temp].adapt;
for (j=0;j<N;j++)
group[i].f[j]=grouptemp[temp].f[j];
}
}
void jiaopei()
{
int i,j,c,d,t,point,r;
int jiaopeiflag[num];
int  temp,temp1,temp2;
double p;
srand(time(NULL));
t=0;
for (i=1;i<num;i++)
{
p=rand()%100;
p=p/100;
if (p<pc)
jiaopeiflag[t++]=i;
}
t=t/2*2;
c=0;
d=1;
for (i=0;i<t/2;i++)
{
temp1=jiaopeiflag[c];
temp2=jiaopeiflag[d];
point=rand()%N;//以point为分支交换
r=rand()%2;
if (r==0)
{
for (j=0;j<=point;j++)//交换前面
{
temp=group[temp1].f[j];
group[temp1].f[j]=group[temp2].f[j];
group[temp2].f[j]=temp;
}
}
else//交换后面
{
for (j=point;j<N;j++)
{
temp=group[temp1].f[j];
group[temp1].f[j]=group[temp2].f[j];
group[temp2].f[j]=temp;
}
}
c=c+2;
d=d+2;
}
}
void bianyi()
{
int bianyiflag[num];
double t;
int i,j,k,temp;
memset(bianyiflag,0,sizeof(bianyiflag));
srand(time(NULL));
for (i=1;i<num;i++)
{
t=rand()%100;
t=t/100;
if (t<pm)
bianyiflag[i]=1;
}
for (i=1;i<num;i++)
if (bianyiflag[i]==1)
{
temp=rand()%N;
k=rand()%100;
group[i].f[temp]=k;
}
}
void select()
{
int i,max,t;
sort(group,group+num,cmp);
for (i=0;i<N;i++)
printf(" x%d=%d",i+1,group[0].f[i]);
printf("\n");
printf("最大值为:%d\n",group[0].adapt);
return;
}
int main()
{
int i,j,t;
initgroup();
t=0;
while(t<MAX)
{
evalute();
choose();
jiaopei();
bianyi();
t++;
}
select();
return 0;

}




当然这还不是最优解,之前跑过一个48957的.

姜启源的书:

    4.1奶制品的生产与销售

  建模还是比较容易的

  转化为式子:

maxz=72x1+64x2

x1+x2<=50

12x1+8x2<=480

3x1<=100

x1,x2>=0,x1,x2为整数(我这里是假设牛奶一桶不可分割,姜启源的书上默认是可以的,无伤大雅)

>> f=[-72;-64];
>> a=[1,1;12,8;3,0];
>> b=[50;480;100];
>> c=[1,2];%x1,x3是整数解
>> [x,fval]=intlinprog(f,c,a,b,[],[],zeros(2,1),[])

x =

20.0000
30.0000

fval =

-3.3600e+03


第一问修改目标函数为maxz=72x1+64x2-35x1-35x2=37x1+29x2

经运算发现结果不变,所以运送方案无需更改

第二问没看懂

第三问修改-72为-90发现运送方案无需更改

4.2自来水的输送

一开始没想明白,后来发现总收入和管理费用是固定的,这样易得

minz=160x11+130x12+220x13+170x14+140x21+130x22+190x23+150x24+190x31+200x32+230x33

x1+x2+x13+x14=50

x21+x22+x23+x24=60

x31+x32+x33=50

30<=x11+x21+x31<=80

70<=x12+x22+x32<=140

10<=x13+x23+x33<=30

10<=x14+x24<=50

这个求解打的我要报警了....

f=[160,130,220,170,140,130,190,150,190,200,230];
a=[1 0 0 0 1 0 0 0 1 0 0;
      -1 0 0 0 -1 0 0 0 -1 0 0;
       0 1 0 0 0 1 0 0 0 1 0 ;
       0 -1 0 0 0 -1 0 0 0 -1 0;
      0 0 1 0 0 0 1 0 0 0 1;
      0 0 -1 0 0 0 -1 0 0 0 -1;
      0 0 0 1 0 0 0 1 0 0 0;
      0 0 0 -1 0 0 0 -1 0 0 0;];
 b=[80;-30;140;-70;30;-10;50;-10];
c=[1 1 1 1 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 1 1 1];
d=[50;60;50];
 [x,fval]=linprog(f,a,b,c,d,zeros(11,1),[])


结果:

x =

0.0000
50.0000
0.0000
0.0000
0.0000
50.0000
0.0000
10.0000
40.0000
0.0000
10.0000

fval =

2.4400e+04


也就是x11,x12.x13.....x32,x33,x34的解其中xij代表从第i个水库运水取第j个小区

与姜启源的结果一致。

例4.3汽车生产与原油采购

   这题建模比较简单   

易得

maxz=2x1+3x2+4x3

1.5x1+3x2+5x3<=600

280x1+250x2+400x3<=60000

x1,x2,x3>=0

>>f=[-2,-3,-4];
>> a=[1.5 3 5;280 250 400];
>> b=[600;60000];
>> c=[1,2,3];
>> [x,fval]=intlinprog(f,c,a,b,[],[],zeros(3,1),[])
结果:

x =

64.0000
168.0000
0

fval =

-632
当然这里fval也要取负值


结果与姜启源一致
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: