首先推荐一篇不错的博客点击打开链接
有关线性规划和非线性规划的实数解解法在前一篇文章有过详细的介绍点击打开链接
而现在引入的是整数规划问题,这里整数指的就是解向量有一个或多个要为整数,实际问题中无法切割的物品,比如人,电脑,手机,都是属于这类范畴~~
这里提供一个比较新的、专用于求解整数规划和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
>> 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
题目:
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
上面都是线性规划的整数规划(约束条件和目标函数都是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[N]; 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
与姜启源的结果一致。
例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也要取负值