声振论坛

 找回密码
 我要加入

QQ登录

只需一步,快速开始

查看: 3196|回复: 1

[经典算法] 单纯型法解线性规划问题(两阶段法)

[复制链接]
发表于 2005-11-16 15:31 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?我要加入

x
<P>/*************************************************************************<BR>                    单纯型法解线性规划问题(两阶段法)        <BR><BR>编程环境:VC++6.0     <BR>方程组输入说明:<BR>变量非负,按提示输入相关参数。<BR>*************************************************************************/<BR>#include &lt;stdio.h&gt;<BR>#include &lt;stdlib.h&gt;<BR>#define MAX 100<BR>#define STP 100
<br>int stop=1; //迭代记数变量<BR>int status; //iterative迭代返回值:1唯一最优,0无界解,-1无穷多最优解 -2迭代超过限制次数<BR>int step=1; //目前阶段
<p>double a[MAX][MAX],b[MAX],c[MAX],temp_c[MAX],max=0; //方程组相关系数<BR>int num_x; //变量个数 <BR>int num_st; //约束方程数<BR>int num_ar=0; //人工变量个数<BR>int arti[MAX]; //人工变量下标<BR>int base[MAX]; //基变量下标<BR>int ma_mi; //1为求最大值,2为求最小值
<p>void create(); //建立方程组<BR>void iterative(); //单纯型法迭代<BR>void output(); //输出结果<BR>void banner(); //打印程序标题<BR>void exchange(); //交换两阶段价值系数<BR>void show(); //输出方程组
<p>void main() {<BR>int i,j,k;<BR>banner();<BR>create();<BR>//保存原价值系数,转换为第一阶段价值系数<BR>for(i=1;i&lt;=num_x;i++) {<BR>  k=0;<BR>  for(j=1;j&lt;=num_ar;j++) if(i==arti[j]) k=1;<BR>  if(k==1) temp_c=-1;<BR>  else temp_c=0;<BR>}<BR>exchange(c,temp_c);
<p>printf("\n\n第一阶段问题为:\n\n");<BR>show();<BR>step++;<BR>printf("\n\n按回车开始第一阶段迭代");<BR>getchar(); <BR>getchar();<BR>iterative();<BR>if(status==-2) {<BR>  puts("迭代超过限制次数强行终止!\n");<BR>  puts("\n按回车结束");<BR>  getchar();<BR>  exit(0);<BR>}<BR>output();
<p>if(max!=0) {<BR>  puts("\n\n原问题无可行解。\n");<BR>  puts("\n按回车结束");<BR>  getchar();<BR>  exit(0);<BR>}
<p>//转换为第二阶段价值系数<BR>exchange(c,temp_c);<BR>//把人工变量列全设为0<BR>for(i=1;i&lt;=num_ar;i++) {<BR>  c[arti]=0;<BR>  for(j=1;j&lt;=num_st;j++) a[j][arti]=0;<BR>}
<p>puts("\n\n第二阶段问题为:\n\n");<BR>show();<BR>puts("\n\n按回车开始第二阶段迭代");<BR>getchar(); <BR>iterative();<BR>switch(status) {<BR>case 1:<BR>  output();<BR>  puts("\n\n原问题有唯一最优解。\n");<BR>  puts("\n按回车结束");<BR>  getchar();<BR>  exit(0);<BR>case 0:<BR>  puts("\n\n原问题为无界解。\n");<BR>  puts("\n按回车结束");<BR>  getchar();<BR>  exit(0);<BR>case -1:<BR>  output();<BR>  puts("\n\n原问题有无穷多最优解。\n");<BR>  puts("\n按回车结束");<BR>  getchar();<BR>  exit(0);<BR>case -2:<BR>  puts("迭代超过限制次数强行终止!\n");<BR>  puts("\n按回车结束");<BR>  getchar();<BR>  exit(0);<BR>}//switch<BR>}
<p>void banner() {<BR>printf("\t\t****************************************\n");<BR>printf("\t\t         单纯型法解线性规划问题\n");<BR>printf("\t\t                         作者:Thunder\n");<BR>printf("\t\t****************************************\n");<BR>printf("\n");<BR>}
<p>void show() {<BR>//对方程组以自然的格式输出,系数为零的x不显示<BR>//为1的不显示系数1,-1系数只显示负号<BR>int i,j,k;<BR>switch(step) {<BR>case 1:<BR>  printf("min z= ");<BR>  printf("x[%d]",arti[1]);<BR>  for(i=2;i&lt;=num_ar;i++) printf(" + x[%d]",arti);<BR>  break;<BR>case 2:<BR>printf("max z= ");<BR>printf("%lg x[%d]",c[1],1);<BR>for(i=2;i&lt;=num_x;i++) {<BR>  if(c==1) printf(" + x[%d]",i);<BR>  else if(c==-1) printf(" - x[%d]",i);<BR>  else if(c&gt;=0) printf(" +%lg x[%d]",c,i);<BR>  else printf(" %lg x[%d]",c,i);<BR>}<BR>break;<BR>}
<p>printf("\nst:\n");<BR>for(i=1;i&lt;=num_st;i++) {<BR>  k=0;<BR>  for(j=1;j&lt;=num_x;j++) { <BR>   if(a[j]!=0) {<BR>    if(a[j]==1&amp;&amp;k!=0) printf(" + x[%d]",j);<BR>    else if(a[j]==1&amp;&amp;k==0) printf("  x[%d]",j);<BR>    else if(a[j]==-1) printf(" - x[%d]",j);<BR>    else if(a[j]&gt;=0&amp;&amp;k!=0) printf(" +%lg x[%d]",a[j],j);<BR>    else if(a[j]&gt;=0&amp;&amp;k==0) printf(" %lg x[%d]",a[j],j);<BR>    else printf(" %lg x[%d]",a[j],j);<BR>    k=1;<BR>   }<BR>  }<BR>  printf(" == %lg\n",b); <BR>}<BR>printf(" x[1]~x[%d]&gt;=0",num_x);<BR>}
<p>void exchange() {<BR>int i;<BR>double temp[MAX];<BR>for(i=1;i&lt;=num_x;i++) {<BR>  temp=temp_c;<BR>  temp_c=c;<BR>  c=temp;<BR>}<BR>}
<p>void create() {<BR>//输入方程组系数,每个方程输完后回显确认<BR>int i,j,k,re_st[MAX],tnum_x,num_addv=0,num_ba=0;<BR>char confirm;<BR><BR>while(1) {<BR>  printf("请选择:1、求最大值,2、求最小值:(1/2)");<BR>  scanf("%d",&amp;ma_mi);<BR>  if(ma_mi!=1&amp;&amp;ma_mi!=2) printf("输入错误,重新选择。");<BR>  else break;<BR>}<BR><BR>while(1) {<BR>  printf("指定变量个数:");<BR>  scanf("%d",&amp;num_x);<BR>  printf("输入价值系数c1-c%d:\n",num_x);<BR>  for(i=1;i&lt;=num_x;i++) {   <BR>   printf("c%d=",i);<BR>   scanf("%lf",&amp;c);<BR>  }<BR>  if(ma_mi==1) printf("max z= ");<BR>  else printf("min z= ");<BR>  printf("%lg x[%d]",c[1],1);<BR>  for(i=2;i&lt;=num_x;i++) {<BR>   if(c&gt;=0) printf(" +%lg x[%d]",c,i);<BR>   else printf("  %lg x[%d]",c,i);<BR>  }<BR>printf("\n正确吗?:(y/n)");<BR>getchar();<BR>confirm=getchar();<BR>if (confirm=='y') break;<BR>else if(confirm=='n') continue;<BR>}
<p>printf("输入约束方程组个数:");<BR>scanf("%d",&amp;num_st);<BR>for(i=1;i&lt;=num_st;i++) {<BR>  printf("st.%d:\n",i);<BR>  while(1) {<BR>   printf("请选择:1、==,2、&gt;=,3、&lt;= :(1/2/3)");<BR>   scanf("%d",&amp;re_st);<BR>   if(re_st!=1&amp;&amp;re_st!=2&amp;&amp;re_st!=3) printf("输入错误,请重新选择。");<BR>   else break;<BR>  }<BR>  printf("输入技术系数:\n");<BR>  for(j=1;j&lt;=num_x;j++) {  <BR>   printf("a%d=",j);<BR>   scanf("%lf",&amp;a[j]);<BR>  }<BR>  printf("输入资源拥有量:\nb%d=",i);<BR>  scanf("%lf",&amp;b);<BR>  <BR>  printf("st.%i:\n",i);<BR>  printf("%lg x[%d]",a[1],1);<BR>  for(j=2;j&lt;=num_x;j++) {<BR>   if(a[j]&gt;=0) printf(" +%lg x[%d]",a[j],j);<BR>   else printf(" %lg x[%d]",a[j],j);<BR>  }<BR>  switch(re_st) {<BR>   case 1: printf(" == %lg",b); break;<BR>   case 2: printf(" &gt;= %lg",b); break;<BR>   case 3: printf(" &lt;= %lg",b); break;<BR>  }
<p>  while(1) {<BR>   printf("\n正确吗?(y/n)");<BR>   getchar();<BR>   confirm=getchar();<BR>   if (confirm=='y') break;<BR>   else if(confirm=='n') {i-=1; break;}<BR>  }<BR>}
<p>//显示输入的方程组<BR>printf("\n原问题为:\n\n");<BR>if(ma_mi==1) printf("max z= ");<BR>else printf("min z= ");<BR>printf("%lg x[%d]",c[1],1);<BR>for(i=2;i&lt;=num_x;i++) {<BR>  if(c==1) printf(" + x[%d]",i);<BR>  else if(c==-1) printf(" - x[%d]",i);<BR>  else if(c&gt;=0) printf(" +%lg x[%d]",c,i);<BR>  else printf(" %lg x[%d]",c,i);<BR>}
<p>printf("\nst:\n");<BR>for(i=1;i&lt;=num_st;i++) { <BR>  k=0;<BR>  for(j=1;j&lt;=num_x;j++) {<BR>   if(a[j]!=0) {<BR>    if(a[j]==1&amp;&amp;k!=0) printf(" + x[%d]",j);<BR>    else if(a[j]==1&amp;&amp;k==0) printf("  x[%d]",j);<BR>    else if(a[j]==-1) printf(" - x[%d]",j);<BR>    else if(a[j]&gt;=0&amp;&amp;k!=0) printf(" +%lg x[%d]",a[j],j);<BR>    else if(a[j]&gt;=0&amp;&amp;k==0) printf(" %lg x[%d]",a[j],j);<BR>    else printf(" %lg x[%d]",a[j],j);<BR>    k=1;<BR>   }<BR>  }<BR>  switch(re_st) {<BR>   case 1: <BR>    printf(" == %lg\n",b); <BR>    break;<BR>   case 2: <BR>    printf(" &gt;= %lg\n",b); <BR>    break;<BR>   case 3: <BR>    printf(" &lt;= %lg\n",b); <BR>    break;<BR>  }<BR>}<BR>printf(" x[1]~x[%d]&gt;=0\n",num_x);
<p>tnum_x=num_x;<BR>for(i=1;i&lt;=num_st;i++) {<BR>  switch(re_st) {<BR>  case 1:<BR>  case 3:<BR>   num_x+=1;<BR>   break;<BR>  case 2:<BR>   num_x+=2;<BR>   break;<BR>  }<BR>}
<p>//化为标准形式<BR>if(ma_mi==2) for(i=1;i&lt;=tnum_x;i++) c*=-1; //求最小值时,系数变相反数<BR>for(i=1;i&lt;=num_st;i++) {<BR>  switch(re_st) {<BR>   case 1:<BR>    num_addv++;<BR>    num_ba++;<BR>    num_ar++;<BR>    c[tnum_x+num_addv]=0; <BR>    base[num_ba]=arti[num_ar]=tnum_x+num_addv;<BR>    for(j=tnum_x+1;j&lt;=num_x;j++) <BR>     if(j==tnum_x+num_addv) a[tnum_x+num_addv]=1;<BR>     else a[j]=0;<BR>    break;<BR>   case 2:<BR>    num_addv++;<BR>    c[tnum_x+num_addv]=0;<BR>    num_addv++;<BR>    num_ba++;<BR>    num_ar++;<BR>    c[tnum_x+num_addv]=0; <BR>    base[num_ba]=arti[num_ar]=tnum_x+num_addv;<BR>    for(j=tnum_x+1;j&lt;=num_x;j++) <BR>     if(j==tnum_x+num_addv-1) a[tnum_x+num_addv-1]=-1;<BR>     else if(j==tnum_x+num_addv) a[tnum_x+num_addv]=1;<BR>     else a[j]=0;<BR>    break;<BR>   case 3:<BR>    num_addv++;<BR>    num_ba++;<BR>    c[tnum_x+num_addv]=0;<BR>    base[num_ba]=tnum_x+num_addv;<BR>    for(j=tnum_x+1;j&lt;=num_x;j++) <BR>     if(j==tnum_x+num_addv) a[tnum_x+num_addv]=1;<BR>     else a[j]=0;<BR>    break;<BR>  }//switch<BR>}//增加松弛变量、剩余变量、人工变量、确定基变量
<p>//显示标准化后的方程组<BR>printf("\n化为标准形式后:\n\n");<BR>if(ma_mi==1) printf("max z= ");<BR>else printf("max z'= ");<BR>printf("%lg x[%d]",c[1],1);<BR>for(i=2;i&lt;=num_x;i++) { <BR>  k=0;<BR>  for(j=1;j&lt;=num_ar;j++)<BR>  if(i==arti[j]) k=1;<BR>  if(k==1) printf(" -M x[%d]",i);<BR>  else if(c==1) printf(" + x[%d]",i);<BR>  else if(c==-1) printf(" - x[%d]",i);<BR>  else if(c&gt;=0) printf(" +%lg x[%d]",c,i);<BR>  else printf(" %lg x[%d]",c,i);<BR>}
<p>printf("\nst:\n");<BR>for(i=1;i&lt;=num_st;i++) {<BR>  k=0;<BR>  for(j=1;j&lt;=num_x;j++) {<BR>   if(a[j]!=0) {<BR>    if(a[j]==1&amp;&amp;k!=0) printf(" + x[%d]",j);<BR>    else if(a[j]==1&amp;&amp;k==0) printf("  x[%d]",j);<BR>    else if(a[j]==-1) printf(" - x[%d]",j);<BR>    else if(a[j]&gt;=0&amp;&amp;k!=0) printf(" +%lg x[%d]",a[j],j);<BR>    else if(a[j]&gt;=0&amp;&amp;k==0) printf(" %lg x[%d]",a[j],j);<BR>    else printf(" %lg x[%d]",a[j],j);<BR>    k=1;<BR>   }<BR>  }<BR>  printf(" == %lg\n",b); <BR>}<BR>printf(" x[1]~x[%d]&gt;=0",num_x);<BR>}
<p>void iterative() {<BR>int i,j,k,k_a,k_f,l; //k_a,k_f值为0或1,记录当前下标在arti[]或base[]里的搜索结果<BR>int base_elem;<BR>int base_out,base_in;<BR>double sigma[MAX],temp;<BR>double value_be; //高斯消元里保存主元素值
<p>printf("\n\n第%d次迭代:\n\n",stop); <BR>for(i=1;i&lt;=num_st;i++) {<BR>  printf("c%d=%lg\t",base,c[base]);<BR>  printf("b%d=%lg\t",i,b);
<p>  switch(step) {<BR>   case 1:<BR>    for(j=1;j&lt;=num_x;j++)<BR>    {<BR>     printf("a[%d][%d]=%lg\t",i,j,a[j]);<BR>    }<BR>    printf("\n");<BR>    break;<BR>   case 2:<BR>    for(j=1;j&lt;=num_x;j++) {<BR>     k_a=0;<BR>     for(l=1;l&lt;=num_ar;l++) if(j==arti[l])k_a=1;<BR>     if(k_a!=1) printf("a[%d][%d]=%lg\t",i,j,a[j]);<BR>    }<BR>    printf("\n");<BR>    break;<BR>  }<BR>}<BR>//求检验数sigma<BR>for(i=1;i&lt;=num_x;i++) {<BR>  sigma=c;<BR>  for(j=1;j&lt;=num_st;j++) sigma-=c[base[j]]*a[j];<BR>  for(j=1;j&lt;=num_st;j++) if(i==base[j]) sigma=0;<BR>  switch(step) {<BR>   case 1:<BR>    printf("sigma[%d]=%lg\t",i,sigma);<BR>    break;<BR>   case 2:<BR>    k_a=0;<BR>    for(l=1;l&lt;=num_ar;l++) if(i==arti[l]) k_a=1;<BR>    if(k_a!=1) printf("sigma[%d]=%lg\t",i,sigma);<BR>    break;<BR>  }<BR>}<BR>putchar('\n');<BR>//检验检验数sigma是否全小于等于0<BR>k=0;<BR>for(i=1;i&lt;=num_x;i++) {<BR>  if(sigma&gt;0) <BR>  k=1;<BR>}<BR>if(k==0) {<BR>  //sigma是全小于等于0时,检查是否为无穷多最优解<BR>  for(i=1;i&lt;=num_x;i++) { <BR>   k_f=k_a=0;<BR>   for(j=1;j&lt;=num_ar;j++)<BR>   if(i==arti[j]) k_a=1;<BR>   if(sigma==0&amp;&amp;k_a!=1) {<BR>    for(j=1;j&lt;=num_st;j++) if(i==base[j]) k_f=1;<BR>   if(k_f==0) {status=-1; return;}<BR>   }<BR>  }<BR>  status=1; <BR>  return;<BR>}<BR>//检查是否为无界解<BR>for(i=1;i&lt;=num_x;i++) { <BR>  k_f=0;<BR>  if(sigma&gt;0) {<BR>   for(j=1;j&lt;=num_st;j++) if(a[j]&gt;0) k_f=1;<BR>   if(k_f!=1) {status=0; return;}<BR>  }<BR>}
<p>//确定换入变量<BR>for(i=1;i&lt;=num_x;i++) { <BR>  k=0;<BR>  for(j=1;j&lt;=num_st;j++) if(i==base[j]) k=1;<BR>  if(k==0&amp;&amp;sigma&gt;0) temp=sigma-1;<BR>}//temp赋初值<BR>for(i=1;i&lt;=num_x;i++) {<BR>  k=0;<BR>  for(j=1;j&lt;=num_st;j++) if(i==base[j]) k=1;<BR>  if(k==0)<BR>   if(sigma&gt;temp&amp;&amp;sigma&gt;0) {<BR>    base_in=i;<BR>    temp=sigma;<BR>   }<BR>}
<p>//确定换出变量<BR>for(i=1;i&lt;=num_st;i++) <BR>  if(a[base_in]&gt;0) {<BR>   temp=b/a[base_in]+1;<BR>   break;<BR>  }//temp赋初值<BR>for(i=1;i&lt;=num_st;i++) {<BR>  if(b/a[base_in]&lt;=temp&amp;&amp;a[base_in]&gt;0) {<BR>   for(j=1;j&lt;=num_ar;j++)<BR>    if(base==arti[j]) { <BR>     base_out=base;<BR>     base_elem=i;<BR>     temp=b/a[base_in];<BR>     break;<BR>    }<BR>  }//人工变量优先换出<BR>  if(b/a[base_in]&lt;temp&amp;&amp;a[base_in]&gt;0) {<BR>   base_out=base;<BR>   base_elem=i;<BR>   temp=b/a[base_in];<BR>  }<BR>}
<p>printf(" 基变量:");<BR>for(i=1;i&lt;=num_st;i++) printf("x[%d] ",base);<BR>printf("换入变量:x[%d] 换出变量:x[%d]",base_in,base_out);<BR>//基变量变换,进行新方程初始化后迭代<BR>for(i=1;i&lt;=num_st;i++) {<BR>  if(base==base_out) base=base_in;<BR>}<BR>//初始化主元素行系数<BR>value_be=a[base_elem][base_in];<BR>b[base_elem]/=value_be;<BR>for(i=1;i&lt;=num_x;i++) a[base_elem]/=value_be;
<p>for(i=1;i&lt;=num_st;i++) {<BR>  if(i!=base_elem) {<BR>   b-=b[base_elem]*a[base_in];<BR>   value_be=a[base_in];<BR>   for(j=1;j&lt;=num_x;j++) a[j]-=a[base_elem][j]*value_be;<BR>  }<BR>}<BR>stop++;<BR>if(stop&gt;STP) {status=-2; return;}<BR>iterative();<BR>}
<p>void output() {<BR>int i,j;<BR>double X[MAX];<BR>printf("\n结果如下:\n");<BR>printf("\nX=(");<BR>for(i=1;i&lt;=num_x;i++) {<BR>  for(j=1;j&lt;=num_st;j++)<BR>  if(i==base[j]) {X=b[j];break;}<BR>  else X=0;<BR>  printf("%lg ",X);<BR>}<BR>printf(")");<BR>for(i=1;i&lt;=num_x;i++) max+=c*X;<BR>if(ma_mi==1) printf("\nMax z= %lf\n",max);<BR>else printf("\nMin z= %lf\n",-max);<BR>}
回复
分享到:

使用道具 举报

发表于 2006-7-20 18:42 | 显示全部楼层
调试过吗
您需要登录后才可以回帖 登录 | 我要加入

本版积分规则

QQ|小黑屋|Archiver|手机版|联系我们|声振论坛

GMT+8, 2024-5-21 05:46 , Processed in 0.049835 second(s), 17 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表