运筹学运输问题课程设计报告Word下载.docx
《运筹学运输问题课程设计报告Word下载.docx》由会员分享,可在线阅读,更多相关《运筹学运输问题课程设计报告Word下载.docx(22页珍藏版)》请在冰豆网上搜索。
77
销量
72
102
41
215
解决方法用表上作业法,具体原理和方法如下:
观察运输问题的线性规划模型可知:
它有m*n具变量,(m+n)个约束方程,其系数矩阵为0-1矩阵,且有大量的零,通常称为稀疏矩阵,形如:
x11x12…x1nx21x22…x2n…xm1xm2…xmn
易知此矩阵的任何一个m+n阶子方阵对应的行列式等于零,所以系数矩阵的秩≤m+n-1,并可证明运输问题的约束方程组系数矩阵的秩为m+n-1.
由此可知运输问题只有m+n-1个独立的约束方程,即其基本可行解中基变量个数为m+n-1,其余均为非基变量。
由于运输问题的以上特征,可用更简便的方法进行计算,即表上作业法。
表上作业法原理同于单纯形法,首先给出一个初始的调运方案(实际上是初始基本可行解),求出各非基变量的检验数去判定当前解是否为最优解,若不是则进行方案调整(即从一个基本可行解转换成另一个基本可行解),再判定是否为最优解,重复以上步骤,直到获得最优解为止。
这些步骤在表上进行十分方便。
操作过程在表上进行,具体的表如下:
表2
x11
x12
x13
x21
x22
x23
x31
x32
x33
初始调运方案如下表:
表3
56
×
41
16
61
上表中“×
”表示非基变量。
最优解的判定如下表
ui
12
vj
上表中带圈的数字所表示的是非基变量。
若令λij=dij-(ui+vj)(dij为非基变量所在的空格处的运费),称λij为空格检验数。
可以证明λij就是单纯形法中的检验数。
所以用判定最优解的原则也同于单纯形法中的判定定理。
当λij>
0时,即可得到最优解,若λij≯0,则返回上一级操作。
直到得到最优解。
(二)运输问题课程设计源程序代码
//#include"
stdafx.h"
#include<
fstream>
iomanip>
iostream>
cmath>
usingnamespacestd;
#definea(j)(*(C+(M-1)*N+j))//销量数组
#defineb(i)(*(C+i*N+N-1))//产量数组
#definec(i,j)(*(C+i*N+j))//运价数组
#definex(i,j)(*(X+i*(N-1)+j))//运量数组
constdoubleBIG_NUM=1.0E15;
//任意大数
//(<
BIG_NUM:
基本解,>
=BIG_NUM:
运量为0)
#defines(i,j)(*(S+i*(N-1)+j))//检验数数组Sij*/
#defineu(i)(*(U+i))//位势数组Ui
#definev(i)(*(V+i))//位势数组Vi
#definecpi(k)((CP+k)->
i)//闭回路点i标
#definecpj(k)((CP+k)->
j)//闭回路点j标
#definecpf(k)((CP+k)->
f)//闭回路点f标
/*
f=0:
j++;
f=1:
i--;
f=2:
j--;
f=3:
i++;
*/
voidTP(intM,intN,double*C,double*X);
intmain()
{
intM,N,i,j;
double*C;
//存储运价,产量及销量
double*X;
//存储运量分配方案
doublez;
ifstreaminfile;
charfn[80];
doublesum;
cout.setf(ios_base:
:
left,ios_base:
adjustfield);
fixed,ios_base:
floatfield);
cout.precision(3);
cout<
<
"
请输入数据文件名:
"
;
cin>
>
fn;
infile.open(fn);
if(!
infile)
文件打开失败!
\n"
system("
pause"
);
exit(0);
}
infile>
M>
N;
M++;
N++;
X=newdouble[sizeof(double)*(M-1)*(N-1)];
C=newdouble[sizeof(double)*M*N];
//把运价,供应量和需求量的数据读入到数组c(i,j)
for(i=0;
i<
M;
++i)
for(j=0;
j<
++j)
z;
c(i,j)=z;
infile.close();
\n=============数据文件================\n"
setw(10)<
c(i,j);
endl;
TP(M,N,C,X);
//输出产销分配方案
\n=============最优解===================\n"
sum=0;
M-1;
N-1;
if(x(i,j)>
=BIG_NUM)
******"
else
x(i,j);
sum+=(x(i,j)*c(i,j));
//cout<
\n\n\tTheminCostis:
%-10.4f\n"
sum);
\n\n\t最高产量:
sum<
//我们现在是在求max,max=-min
free(X);
free(C);
return0;
//记录闭回路点结构
structPATH
inti,j,f;
};
voidTP(intM,intN,double*C,double*X)
double*U,*V,*S;
intMN1,m,n;
structPATH*CP;
intk,i,j,l,k1,l1,ip;
doubleCmin,sum;
intI0,J0,Imin,Jmin;
intfi,fj,fc,f;
MN1=(M-1)+(N-1)-1;
m=M-1;
n=N-1;
S=newdouble[sizeof(double)*(M-1)*(N-1)];
U=newdouble[sizeof(double)*M];
V=newdouble[sizeof(double)*N];
CP=newPATH[sizeof(structPATH)*(MN1+1)];
//解初始化Xij=BIG_NUM
m;
n;
x(i,j)=BIG_NUM;
//最小元素法求初始可行解
for(k=0;
k<
MN1;
++k)
Cmin=BIG_NUM;
for(i=0;
i<
m;
++i)
fi=0;
for(l=0;
l<
k;
++l)
//去除已经用过的行
if(i==cpi(l))
fi=1;
break;
if(fi==1)
continue;
for(j=0;
j<
n;
++j)
fj=0;
//去除已经用过的列
if(j==cpj(l))
fj=1;
if(fj==1)
if(Cmin>
c(i,j))
Cmin=c(i,j);
I0=i;
J0=j;
}//endforj
}//endfori
//得到了未划去的最小运价所在格的坐标(I0,J0)和最小运价Cmin
if(k>
0)
if(Cmin==BIG_NUM&
&
cpi(k-1)==0)
for(l1=0;
l1<
l1++)
if(x(l1,cpj(k-1))==BIG_NUM)
x(l1,cpj(k-1))=0;
elseif(Cmin==BIG_NUM&
cpi(k-1)!
=0)
if(x(cpi(k-1),l1)==BIG_NUM)
x(cpi(k-1),l1)=0;
if(b(I0)<
a(J0))
cpi(k)=I0;
cpj(k)=-1;
x(I0,J0)=b(I0);
a(J0)-=b(I0);
b(I0)=0;
cpi(k)=-1;
cpj(k)=J0;
x(I0,J0)=a(J0);
b(I0)-=a(J0);
a(J0)=0;
}//endfork用最小元素法求得了初使可行解
//输出初始可行解
cout<
\n=============初始解===================\n"
sum=0;
M-1;
i++)
N-1;
j++)
if(x(i,j)>
=BIG_NUM)
setw(10)<
x(i,j);
sum+=(x(i,j)*c(i,j));
endl;
\n\n\t初始产量:
//我们现在是在求max,max=-min
system("
);
while(true)
//位势置初值Ui,Vi=BIG_NUM
u(i)=BIG_NUM;
v(j)=BIG_NUM;
//求位势
l=0;
u(0)=0;
if(u(i)>
=BIG_NUM&
v(j)>
x(i,j)<
BIG_NUM)
{//记录未求过位势的位置
cpi(l)=i;
cpj(l)=j;
l++;
elseif(x(i,j)<
BIG_NUM&
u(i)<
v(j)=c(i,j)-u(i);
v(j)<
u(i)=c(i,j)-v(j);
//按记录位置求其余位势
if(l>
0)
while(true)
ip=0;
for(k=0;
k<
l;
k++)
i=cpi(k);
j=cpj(k);
{//记录未求过位势的位置
cpi(ip)=i;
cpj(ip)=j;
ip++;
}//endfork
if(ip==0)
l=ip;
}//endforwhile
//求检验数
j++)
s(i,j)=BIG_NUM;
=BIG_NUM)
s(i,j)=c(i,j)-u(i)-v(j);
//求最小检验数
i++)
if(Cmin>
s(i,j))
Cmin=s(i,j);
I0=i;
J0=j;
=0)
return;
//已经得到最优解,返回主程序
//此时找到了入基变量X(I0,J0)
//求闭回路
k++)
cpf(k)=-1;
cpi(0)=I0;
cpj(0)=J0;
k=0;
while(true)
f=cpf(k);
//设置闭回路搜索方向
i=cpi(k);
j=cpj(k);
fc=0;
f++;
cpf(k)=f;
if(f>
=4)
//避免反向搜索
if(k>
if(f==0&
cpf(k-1)==2)
elseif(f==1&
cpf(k-1)==3)
elseif(f==2&
cpf(k-1)==0)
elseif(f==3&
cpf(k-1)==1)
if(f==0)
{//沿j+方向搜索
while(true)
if(j>
=n)
{fc=2;
if(i==I0&
j==J0)
{fc=1;
if(s(i,j)>
{fc=3;
}//endforj+
elseif(f==1)
{//沿i-方向搜索
if(i<
if(s(i,j)>
}//endfori-
elseif(f==2)
{//沿j-方向搜索
if(j<
}//endforj-
elseif(f==3)
{//沿i+方向搜索
if(i>
=m)
}//endfori+
if(fc==1||fc==3)
}//endforwhileflag2
if(fc==0)
k--;
//沿此方向搜索失败,退回到前一点
elseif(fc==1)
//搜索完成
elseif(fc==3)
{//沿此方向搜索成功,前进一点
k++;
cpi(k)=i;
cpj(k)=j;
}//endwhile
//去除闭回路中的非转折点
while(l<
k-1)
i=l+1;
while(i<
=k)
if(cpf(l)==cpf(i))
(l+1))
j=l+1;
k1=k-(i-j);
//如果某些点前进方向相同,则去除中间各点
while(i<
cpi(j)=cpi(i);
cpj(j)=cpj(i);
cpf(j)=cpf(i);
l+=2;
k=k1;
}//endforwhilel<
k-1
//查找闭回路上基本解的最小值
Cmin=x(cpi
(1),cpj
(1));
Imin=cpi
(1);
Jmin=cpj
(1);