运筹学实验单纯形法上机报告.docx
- 文档编号:25784166
- 上传时间:2023-06-14
- 格式:DOCX
- 页数:32
- 大小:1.70MB
运筹学实验单纯形法上机报告.docx
《运筹学实验单纯形法上机报告.docx》由会员分享,可在线阅读,更多相关《运筹学实验单纯形法上机报告.docx(32页珍藏版)》请在冰豆网上搜索。
运筹学实验单纯形法上机报告
单纯形法—大M法实验报告
一、实验目的
使用目前熟悉的语言,实现所学的单纯形法之大M法,并正确运算测试结果。
本组成员使用C语言实现。
二、单纯形法及大M法
1.单纯形法(SimplexMethod)
(1)单纯形法是解线性规划问题的一个重要方法。
其原理的基本框架为:
第一步:
将LP线性规划变标准型,确定一个初始可行解(顶点)。
第二步:
对初始基可行解最优性判别,若最优,停止;否则转下一步。
第三步:
从初始基可行解向相邻的基可行解(顶点)转换,且使目标值有所改善—目标函数值增加,重复第二和第三步直到找到最优解。
(2)用程序进行运算前,要将目标函数及约束方程变成标准形式。
对于非标准形式须作如下变换:
a)目标函数为极小值minz=CX时,转换为maxz=-CX形式;
b)在约束方程中有“≤”时,在加上一个松弛变量;
c)在约束方程中有“≥”时,采用减去一个松弛变量,再加上一个人工变量;
d)在约束方程中有“=”时,加上一个人工变量;
e)所有的人工变量,松弛变量的目标函数系数置为0。
(3)对于标准形式的线性规划问题。
用单纯形法计算步骤的框图
(4)在程序运算过程中,采用单纯形表显示运算过程。
2.大M法
(1)方法:
在约束条件中,加入人工变量后,要求目标函数不受影响,目标函数中人工变量的系数取–M(M为系统所能表示范围内的一个非常大的值本程序取1000000),其运算过程同单纯形法。
(2)理由:
目标函数实现最大化,就必须将人工变量从基变量中换出,否则目标函数就不可能取得最大化。
三、数据结构及模块设计
1.程序中用到的数据结构:
#defineM20//最大20个变量
#defineN40//40个约束方程
#defineMax1000000//大M
doubleD[M][N];//系数矩阵
doubleC[M];//目标函数系数
doubleCb[M];//基向量系数
doubleB[M];//约束常数
doubleValue[N];//检验数
intXb[M];//基向量
doubleX0[M];//可行解
intop[M];//约束方程符号0---"<"、1---"="、2---">"
intm,n;//矩阵行数、列数
intbegin_n;//初始变量数
intIn_BaseX=-1;//进基变量
intin_n=-1;//进基列标示
intout_m=-1;//出基行标示
intOut_BaseX=-1;//出基变量
intbest;//最优函数返回值
charname[30];//文件名
intManX_num=0;//人工变量数目
intManX_list[M];//人工变量存放数组
2.模块设计:
voidread();//读取方程子函数
voidprint();//显示单纯表子函数
voidinit_change();//初始变换子函数
voidcompute_value();//计算检验数子函数
intbest_Result();//判断是否得到最优解子函数
voidin_base();//进基选子函数
voidout_base();//出基选择子函数
voidrow_change();//行变换子函数
四、详细设计
1.文件格式定义
格式:
(行数/约束方程数:
列数/变量数:
)
mn
(约束矩阵:
符号:
0小于,1等于,2大于B值)
D11D12D13…Dn1op1b1
D21D22D23…Dn2op2b2
….
Dm1D2mDm3…Dnmopmbm
(最大值/最小值:
1最大,2最小)
max/min
目标函数的变量系数:
C1C2C3….Cn
例:
32
0.60.5012000
0.40.104000
00.406000
1
2510
2.voidread()读取约束矩阵、目标函数
voidread(){
FILE*fp;//文件
inti=0,j=0,k;
fp=fopen(name,"r");
if(fp!
=NULL){//读变量数目和约束方程个数m,n
fscanf(fp,"%d",&m);
fscanf(fp,"%d",&n);
}
begin_n=n;//初始(未经过标准化)变量数置为n,
for(i=0;i for(j=0;j if(fp! =NULL) fscanf(fp,"%lf",&D[i][j]); else printf("error"); if(fp! =NULL)//读约束方程符号 fscanf(fp,"%d",&op[i]); else printf("error"); if(fp! =NULL)//读取常数值 fscanf(fp,"%lf",&B[i]); else printf("error"); } if(fp! =NULL)//读取目标函数类型 fscanf(fp,"%d",&Type); else printf("error"); for(k=0;k if(fp! =NULL) fscanf(fp,"%lf",&C[k]); else printf("error"); fclose(fp); }//voidread() 3.voidprint()单纯形表显示函数 voidprint(){ inti=0,j=0; voidline_V(int);//竖线子函数 voidline_R(int);//横线子函数 voidln();//换行子函数 voidspace();//空格子函数 ln();//第1条直线 line_R(15+n*5); ln(); //显示第1行“C|C1C2C3...” space(6); printf("C"); space(7); line_V (1); for(i=0;i if(C[i]==-Max) printf("-M"); else printf("%5.1lf",C[i]); ln();//第2条直线 line_R(15+n*5); ln(); //显示第2行“CbXbB|X1X2X3...” printf("CbXbB"); line_V (1); for(i=0;i printf("X%-2d",i+1); ln();//第3条直线 line_R(15+n*5); ln(); //显示第3部分“Cb1Xb1B1|D11D12D13...” //“Cb2Xb2B2|D21D22D23...” //“Cb3Xb3B3|D31D32D33...” //“...” for(i=0;i if(Cb[i]==-Max) printf("-M"); else printf("%-5.0lf",Cb[i]); printf("X%-2d",Xb[i]+1); printf("%5.0lf",B[i]); line_V (1); for(j=0;j printf("%5.1lf",D[i][j]); ln(); } //第4条直线 line_R(15+n*5); ln(); //显示第4行“Value|Value1Value2Value3...” space(5); printf("Value"); space(4); line_V (1); for(i=0;i if(Value[i]>Max/2){//当Value值达到M数量级时,用aM+b表示 intk=(int)(Value[i]/Max); doublel=Value[i]-k*Max; if(l>Max/2){ k++; l-=Max; } if(k==0) printf(""); elseif(k==1) printf("M"); else printf("%dM",k); if(l==0) printf(""); elseif(l>0) printf("+%-1.0lf",l); else printf("%-2.0lf",l); } elseif(Value[i]<-Max/2){//当Value值达到M数量级时,用aM+b表示 intk=(int)(Value[i]/Max); doublel=Value[i]-k*Max; if(l<-Max/2){ k--; l+=Max; } if(k==0) printf(""); elseif(k==-1) printf("-M"); else printf("%dM",k); if(l==0) printf(""); elseif(l>0) printf("+%-1.0lf",l); elseif(l<0) printf("%-2.0lf",l); } else//正常显示 printf("%4.1lf",Value[i]); ln();//第5条直线 line_R(15+n*5); ln(); //显示第5行“X(0)=(X1,X2,X3...)” space (1); printf("X(0)=("); for(i=0;i printf("%.2lf,",X0[i]); } printf("%.1lf",X0[i]); printf(")"); ln(); line_R(15+n*5);//第6条直线 ln(); } //**************横线*************** voidline_R(intn){ inti; for(i=0;i printf("-"); } //**************竖线*************** voidline_V(intn){ inti; for(i=0;i printf("|"); } //**************空格*************** voidspace(intn){ inti; for(i=0;i printf(""); } //**************换行*************** voidln(){ printf("\n"); } 4.voidinit_change()初始矩阵变换,加入松弛变量和人工变量 voidinit_change(){ inti=0,j; intbase_variable(intx);//判断是否为基变量的子函数 //对">="约束方程,减去松弛变量,目标系数为0 for(i=0;i if(op[i]==2){ n++; C[n-1]=0; for(j=0;j if(j==i) D[j][n-1]=-1; else D[j][n-1]=0; } } } for(i=0;i //对有">="和"="约束方程,加上人工变量,目标系数为M if(op[i]==2||op[i]==1){ n++; ManX_list[ManX_num]=n-1;//将人工变量下标存入人工变量表 ManX_num++;//人工变量数目加1 Xb[i]=n-1; C[n-1]=-Max;//人工变量的系数去-M Cb[i]=C[n-1]; for(j=0;j if(j==i) D[j][n-1]=1; else D[j][n-1]=0; } } //对有"<="约束方程,加上松弛变量,目标系数为0 else{ n++; Xb[i]=n-1; C[n-1]=0; Cb[i]=C[n-1]; for(j=0;j if(j==i) D[j][n-1]=1; else D[j][n-1]=0; } } } //如果是求最小值,则通过将目标函数各变量系数去相反数 if(Type==2){ for(i=0;i C[i]=-C[i]; } //初始可行解 for(i=0;i if((j=base_variable(i))! =-1) X0[i]=B[j]; else X0[i]=0; }//init_change() intbase_variable(intx){//******判断是否为基变量,若是,返回下标,否则返回-1******** intj; for(j=0;j if(x==Xb[j]) returnj; } return-1; } 5.voidcompute_value()计算检验数 voidcompute_value(){ inti,j,k; intbase_variable(intx);//判断是否为基变量的子函数 for(i=0;i if((j=base_variable(i))! =-1)//基变量的检验数为0 Value[i]=0; else{//非基变量Xi的检验数为Ci-Cb*D[m][i] doublesum=0; for(k=0;k sum+=Cb[k]*D[k][i]; Value[i]=C[i]-sum; } }//compute_value() 6.intbest_Result()判断是否得到最优解。 intbest_Result(){//唯一最优1,无穷多最优2,无界3,无可行5,未得到返回4 inti; intless=0,more=0,equal=0;//检验数各种情况的数目小于0,大于0,等于0; intonly_more=-1;//当只有一个检验数大于0时,记录进基变量的列数 for(i=0;i if(Value[i]<0) less++; elseif(Value[i]==0) equal++; elseif(Value[i]>0){ more++; only_more=i; } if(more==0){//无检验数大于0 //若基解中有人工变量不为0,则无可行解 for(i=0;i if(X0[ManX_list[1]]! =0) return5; //非基变量检验数至少一个等于0,得到无穷多最优解 for(i=0;i if(Value[i]! =0&&base_variable(i)! =-1) return2; //检验数全部小于0,得到唯一最优解 else return1; } //检验数只有1个大于0,并且无出基变量,得到无界解 elseif(more==1){ for(i=0;i if(D[i][only_more]>0) return4;//有一个大于0,不能判断 return3;//全部小于0,无出基变量,得到无界解 } //检验数至少有2个大于0,不能判断 else return4; }//best_Result() fvoidin_base();//进基选子函数 voidout_base();//出基选择子函数 voidrow_change();//行变换子函数 7.voidin_base()进基选子函数 voidin_base(){ doublemax=0;inti; intmax_num=-1;//初始最大的检验数下标为-1 for(i=0;i if(Value[i]>max){ max=Value[i]; max_num=i; in_n=i; } } In_BaseX=max_num;//存到全局变量In_BaseX }//in_base() 8.voidout_base()出基选择子函数 voidout_base(){ doubletemp[M]; inti; intin=In_BaseX; doublemin=Max; intmin_num=-1;//初始最小B/Dij下标为-1 for(i=0;i //D值为零,D if(D[i][in]>0) temp[i]=B[i]/D[i][in]; else temp[i]=Max; } for(i=0;i if(temp[i] min=temp[i]; min_num=Xb[i]; out_m=i; } } Out_BaseX=min_num;//存到全局变量Out_BaseX }//out_base() 9.voidrow_change()行变换子函数 voidrow_change(){ inti,j; doubletemp; Xb[out_m]=In_BaseX;//进基变量进基 //对出基行变换,包括系数矩阵和B值 temp=D[out_m][in_n]; for(j=0;j D[out_m][j]=D[out_m][j]/temp; B[out_m]=B[out_m]/temp; //对其他行变换 for(i=0;i //不是出基行,并且其对应进基列值不为0,变换 if(i! =out_m&&D[i][in_n]! =0){ doublem=D[i][in_n];//倍数 for(j=0;j D[i][j]=D[i][j]-m*D[out_m][j]; B[i]=B[i]-m*B[out_m];//B值变换 } } for(i=0;i Cb[i]=C[Xb[i]]; for(i=0;i if((j=base_variable(i))! =-1)//基变量值为对应B值 X0[i]=B[j]; else//其他变量值为0 X0[i]=0; }//row_change() 五、程序测试及结果 1.第1题 (1)原题 (2)文件存储 (3)读取 (4)初始变换 (5)运算过程 (6)运算结果 2.第2题 (1)原题 (2)文件存储 (3)读取 (4)初始变换 (5)运算过程 (6)运算结果 3.第3题 (1)原题 (2)文件存储 (3)读取 (4)初始变换 (5)运算过程 (6)运算结果 4.第2题 (1)原题 (2)文件存储 (3)读取 (4)初始变换 (5)运算过程 (6)运算结果 因为,X4进基,无出基变量,故有无界解。 5.第2题 (1)原题 (2)文件存储 (3)读取 (4)初始变换 (5)运算过程 (6)运算结果 因为,所有非基变量检验数小于0,并且有人工变量值不为0 六、工作分配及实验感想 1.工作分配 完成程序代码及程序报告: 刘光锐 查找资料及相关书籍: 周威,姚奇森 参与对问题分析与设计: 彭飞,何华刚,刘鹏飞 2.实验感想 这次试验,开始认为很困难,因为对单纯形法本来就不是很熟悉,但是后来看到有很多同学都能完成任务,觉得这虽然是个难题,但如果没去做过,有些遗憾,正好老师给我们把上交期限延长到五一之前,这又给我们了机会,因为我们清楚地知道,大学的实验越来越少,能锻炼自己的机会也越来越少,所以鼓起勇气,一定要去完成。 不会的地方,去问问学的好的同学,都很耐心的告诉,终于经过了1天多的时间,完成了任务,回头看看,困难真是个纸老虎,心里自然有种胜利的感觉。 而且对算法有了更深的印象,在我今后的学习,工作中提供了一种思考方式。 谢谢老师,谢谢运筹课。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 运筹学 实验 单纯 上机 报告
![提示](https://static.bdocx.com/images/bang_tan.gif)