运输问题表上作业法
// T-Problem_Solver.cpp : Defines the entry point for the console application.
// 表上作业法的源代码
#include "stdafx.h"
#include <fstream>
#include <iomanip>
#include <iostream>
#include <cmath>
using namespace std;
#define a(j) (* (C+(M-1)*N+j)) // 销量数组
#define b(i) (* (C+i*N+N-1)) // 产量数组
#define c(i,j) (* (C+i*N+j)) // 运价数组
#define x(i,j) (* (X+i*(N-1)+j)) // 运量数组
const double BIG_NUM = 1.0E15; // 任意大数
// ( < BIG_NUM: 基本解, >= BIG_NUM : 运量为 0 )
#define s(i,j) (*(S+i*(N-1)+j)) // 检验数数组Sij */
#define u(i) (*(U+i)) // 位势数组 Ui
#define v(i) (*(V+i)) // 位势数组 Vi
#define cpi(k) ((CP+k)->i) // 闭回路点 i 标
#define cpj(k) ((CP+k)->j) // 闭回路点 j 标
#define cpf(k) ((CP+k)->f) // 闭回路点 f 标
/*
f = 0: j++;
f = 1: i--;
f = 2: j--;
f = 3: i++;
*/
void TP(int M,int N,double *C,double *X);
int main()
{
int M, N, i, j;
double* C; // 存储运价, 产量及销量
double* X; // 存储运量分配方案
double z;
ifstream infile;
char fn[80];
double sum;
cout.setf(ios_base::left,ios_base::adjustfield);
cout.setf(ios_base::fixed,ios_base::floatfield);
cout.precision(3);
cout<<"请输入数据文件名: ";
cin>>fn;
infile.open(fn);
if (!infile)
{
cout<<"文件打开失败!\n";
system("pause");
exit(0);
}
infile>>M>>N;
M++;
N++;
X=new double[sizeof(double)*(M-1)*(N-1)];
C=new double[sizeof(double)*M*N];
// 把运价, 供应量和需求量的数据读入到数组 c( i, j )
for(i=0;i<M;++i)
for(j=0;j<N;++j)
{
infile>>z;
c(i,j)=z;
}
infile.close();
cout<<"\n============= 数据文件 ================\n";
for(i=0;i<M;++i)
{
for(j=0;j<N;++j)
cout<<setw(10)<<c(i,j);
cout<<endl;
}
system("pause");
TP(M,N,C,X);
// 输出产销分配方案
cout<<"\n============= 最优解 ===================\n";
sum=0;
for(i=0;i<M-1;++i)
{
for(j=0;j<N-1;++j)
if(x(i,j)>=BIG_NUM)
cout<<setw(10)<<"******";
else
{
cout<<setw(10)<<x(i,j);
sum+=(x(i,j)*c(i,j));
}
cout<<endl;
}
//cout<<"\n\n\tThe min Cost is: %-10.4f\n", sum);
cout<<"\n\n\t最高产量:"<<setw(10)<<sum<<endl; //我们现在是在求max,max=-min
free(X);
free(C);
system("pause");
return 0;
}
// 记录闭回路点结构
struct PATH
{
int i,j,f;
};
void TP(int M,int N,double* C,double* X)
{
double *U, *V, *S;
int MN1,m,n;
struct PATH* CP;
int k,i,j,l,k1,l1,ip;
double Cmin,sum;
int I0,J0,Imin,Jmin;
int fi,fj,fc,f;
MN1=(M-1)+(N-1)-1;
m=M-1;
n=N-1;
S=new double[sizeof(double)*(M-1)*(N-1)];
U=new double[sizeof(double)*M];
V=new double[sizeof(double)*N];
CP=new PATH[sizeof(struct PATH)*(MN1+1)];
// 解初始化 Xij = BIG_NUM
for(i=0;i<m;++i)
for(j=0;j<n;++j)
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;
for ( l = 0; l < k; ++l )
// 去除已经用过的列
if ( j == cpj( l ) )
{
fj = 1;
break;
}
if ( fj == 1 )
continue;
if ( Cmin > c( i, j ) )
{
Cmin = c( i, j );
I0 = i;
J0 = j;
}
} // end for j
} // end for i
// 得到了未划去的最小运价所在格的坐标(I0,J0)和最小运价Cmin
if ( k > 0 )
if(Cmin==BIG_NUM && cpi(k-1)==0)
{
for(l1=0;l1<m;l1++)
if(x(l1,cpj(k-1))==BIG_NUM)
x(l1,cpj(k-1))=0;
}
else if(Cmin==BIG_NUM && cpi(k-1)!=0)
for(l1=0;l1<n;l1++)
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;
}
else
{
cpi( k ) = -1;
cpj( k ) = J0;
x( I0, J0 ) = a( J0 );
b( I0 ) -= a( J0 );
a( J0 ) = 0;
}
} // end for k 用最小元素法求得了初使可行解
// 输出初始可行解
cout << "\n============= 初始解 ===================\n";
sum = 0;
for ( i = 0; i < M - 1; i++ )
{
for ( j = 0; j < N - 1; j++ )
if ( x( i, j ) >= BIG_NUM )
cout << setw( 10 ) << "******";
else
{
cout << setw( 10 ) << x( i, j );
sum += ( x( i, j ) * c( i, j ) );
}
cout << endl;
}
cout<<"\n\n\t初始产量:"<<setw(10)<<sum<<endl;//我们现在是在求max,max=-min
system( "pause" );