割平面法编程

云南大学数学与统计学实验教学中心

实验报告

一、实验目的

编程实现割平面整数线性规划问题,加深对割平面法以及单纯形法的理解和掌握

二、实验环境

VS2010(C++)

三、实验内容

在对偶单纯形的基础上,考虑x 的不可分性,也就是不能为小数。这样就需要我们在求的最优解得基础上,保证x的取值为整数。

经过学习,有两种方法可以用来求解:分支定界法,以及割平面法。

割平面法就是通过一定的约束,将非整数解割去,在其凸边上得到相应的整数解。

首先不考虑变量xi是整数这一条件,但是增加线性约束条件(称为割平面),使得原来可行解区域切去一部分,但没有切去任何整数可行解。该方法是指出怎样找到适当的割平面,使得切割后得到可行解区域的某顶点(称极点,对应基本可行解)恰好是整数线性规划问题的最优解

四、实验过程

A、割平面法的算法思想(课本割平面法部分由具体算法P121)

1.给定整数线性规划(ILP)的实例,用原始单纯形算法解决ILP的松弛线性规划(LP),

得到LP的最优基本可行解x,其基为B,最后单纯形表中的第i个方程为(i=1,2,…,m)

xi + ∑k aik xk = bi (5.1) 由于方程5.1中的变量是非负的,则

∑k [aik]xk ≤∑k aik xk (5.2)

从而方程(5.1)可变为

xi + ∑k [aik]xk ≤bi (5.3 因为在ILP中x的限制为整数,从而(5.3)的左边为整数,进而(5.3)的右边也为整数,

于是得到

xi + ∑k [aik]xk ≤[bi] (5.4) 用(5.1)减去(5.4),得到

∑k(aik - [aik])xk ≥bi - [bi] (5.5)

令fik=aik - [aik]和fi=bi - [bi],这里fik(fi)称为aik

(bi)小数部分,满足

0 ≤fik< 1 和0 ≤fi < 1 (5.6)

从而由(5.5)和 (5.6)得到下面的式子然后再按照原单纯形算法经行求解。重复上述步骤。

2. 直到得到的解为整数。才停止运算。

B 、编译运行程序,输入约束方程的系数矩阵A ,常矩阵B,价值系数C,得到最优解

为了保证得到的算法能求得解,并且求的的最优解是对的。这里选取了P118页的例题3。

1、 约束条件

12

12121212max 134,0,z x x x x x x x x x x =+-+≤??+≤??

≥???为整数

2、 整理化简后,得到初始表如下:

Cj

1 1 0 0 CB

XB b x1 x2 x3 x4 0 x3 1 -1 1 1 0 0

x4

4

3

1

1

D 、运行结果如下图:

1)代数上述表中的值:

a 、初始化后的结果:这时候,它是按照对偶单纯形来求解的

b 、对偶单纯形优化后的结果:

得到最优解,但是此时得到的解为小数而非整数解

c、运用割平面法经行优化改进

割平面法添加条件后出事后以及第一次优化的结果

割平面法的第二次第三次优化:

d、最后得到的结果:

最后得到的结果与书上例题所有的结果完全吻合。所以所编写的算法为割平面法。

五、实验总结

通过对割平面算法编程进一步加强了对本章知识的掌握,当然这不局限于割平面法,对分支定界法也有进一步的了解。

六、源代码

这里需要说明的是。这个算法是在对偶单纯形算法的基础上修来得来的。

源代码如下:

#include

#include

using namespace std;

#define M -10000

class DanChun{

public:

double A[100][120],B[30]; //创建一个二维数组,用来存储xi值以及b的值

double A1[100][120],B1[30],C1[110]; //创建一个二维数组,用来存储xi值以及b的值

double C[110],CB[40];//定义一个C矩阵用来存储x 的价值系数

double CZ[110];//CZ用来存储cj-zj的值

double sita[30];//用来存储sita的值

int XB[30];//用来存XB的值

double X[100];//用来存储最后计算的X的值

double w[100]; //Cj-Zj/X[i]的替换。

public:

int n,m;

double favl;

double XZ[100]; // 得到最优解以及xi 的值

double RA[100][120]; // 得到最优解时A的系数

void init();//1.将不等式约束的各矩阵进行赋值

bool FindE(int i, int j);//2.寻找A矩阵中的基向量

void FindCB(); //3.寻找有用价值系数,Cj-Zj需要用到的

int Cj_Zj(); //4.1求出cj-zj的值

int C_sita(int k);//4.2计算sita的值

void Com_DC();//4.用来计算单纯形法的主函数

void Com_E(int l, int k);//4.3求其单位向量

bool P_CjZj();//4.4

int Bbool(double b[], int k); //判断b中是否有负值存在int TH(int l); //b有负值是,进行替换操作

void Display();

void Display1();

void Setinit(int m, int n, double a[][120], double *b);

void Reback();

/*----*/

void Buffer(double b,int k);

void start();

void Gepingmianfa();

bool panduan(double x[100]);

};

//增加条件后,传过来的行数,列数,以及初始值

//a为约束条件系数

//c 为价值系数

//b 为约束系数

void DanChun::init(){

int i=0,j=0;

cout<<"请输入 m,n :";

cin>>m;

cin>>n;

cout<<"请输入线性约束矩阵:"<

for(i=0; i

for(j=0;j

if(j

cin>>A[i][j];

} else {

A[i][j]=0;

if(j==n+i){

A[i][j]=1;

}

}

A1[i][j] = A[i][j];

}

}

cout<

cout<<"请输入B的值:"<

for(i=0;i

cin>>B[i];

B1[i] = B[i];

CB[i]=0;

}

cout<

cout<<"请输入价值系数 C:"<

for(i=0;i

if(i

cin>>C[i];

} else{

C[i] = M;

}

X[i]=0;

C1[i] = C[i];

}

n = m+n;

}

void DanChun::Display(){

int i,j;

cout<<"价值系数 C:";

for(i=0;i

cout<

}

cout<

cout<<"B的值:";

for(i=0;i

cout<

}

cout<

cout<<"线性约束矩阵A:"<

for(i=0; i

for(j=0;j

printf("%0.3lf\t",A[i][j]);

}

cout<

}

cout<

cout<<"价值系数 CB:";

for(i=0;i

cout<

}

cout<

}

bool DanChun::P_CjZj(){

int j;

for(j=0;j

if(CZ[j]>0){

return true;

}

}

return false;

}

int DanChun::TH(int l){

int i=0, k=0;

double min = 1000;

for(i=0; i

w[i] = 0;

}

for(i=0; i

if(A[l][i]>=0){

w[i] = -M;

}else{

w[i] = CZ[i]/A[l][i];

}

}

for(i=0; i

if(min>w[i]){

min = w[i];

k = i;

}

}

return k;

}

int DanChun::Bbool(double b[], int k){ int i=0, l=0, s=0;

double min = 0;

for(i=0; i

if(min>b[i]){

min = b[i];

l = i; //找出行下标

}

}

if(min< 0){

return l;

}

return -1;

}

void DanChun::Display1(){

int i,j=0,p=0;

double favl=0;

for( i=0;i

X[XB[i]]=B[i];

}

for(i=0;i

favl += C[i]*X[i];

}

cout<<"当前为最优解:favl = "<

cout<<"有最优解时,x的取值如下:"<

for(i=0;i

j=i;

cout<<"X["<

}

}

void DanChun::Com_DC(){

int i,j=0,k,l,p=0;

bool b;

double favl=0;

do{

b =true;

k=Cj_Zj();//得到cj-zj的大于0的max

if(k == -1){

if( (l=Bbool(B,m)) >=0){

k = TH(l);

b = false;

} else {

Display1();

return;

}

}

if(b){

l=C_sita(k);

if(l==-1){

cout<<"无解!"<

return;

}

}

CB[l]=C[k];

XB[l]=k;

Com_E(l,k);

p++;

cout<<"----------------------------第"<

cout<

for(i=0;i

cout<

}

cout<

Display();

cout<<"----------------------------第"<

}while(P_CjZj() || !b);

}

void DanChun::Com_E(int l, int k){

int i,j;

B[l]=B[l]/A[l][k];

for(j=0;j

if(j==k) continue;

A[l][j]= A[l][j]/A[l][k];

}

A[l][k]=1;

for(i=0;i

if(i==l)

continue;

for(j=0;j

if(j==k)

continue;

A[i][j]=A[i][j]-A[i][k]*A[l][j];

}

B[i]=B[i]-A[i][k]*B[l];

A[i][k]=0;

}

}

int DanChun::Cj_Zj(){

int i,j,k=0;

double sum=0,max=0;

for(j=0;j

for(i=0;i

sum+=CB[i]*A[i][j];

}

CZ[j]=C[j]-sum;

sum=0;

}

for(j=0;j

if(CZ[j]>max && CZ[j]>0){

max=CZ[j];

k=j;

}

}

if(max==0){

return -1;

}

return k;

}

int DanChun::C_sita(int k){

int i,j=0;

double min=-M;

for(i=0;i

if(A[i][k]>0){

sita[i]=B[i]/A[i][k];

j++;

}else{

sita[i]=-M;

}

}

if(j==0){ //表示没有一个A[i][k]是大于0的

return -1;

}

for(i=0;i

if(sita[i]

min=sita[i];

k=i;

}

}

return k;

}

bool DanChun::FindE(int i,int j){ //判断是否是单位列int k=0;

while(k

if(A[k][j] !=0 && k!=i){

return false;

}else{

k++;

if(k==i){

continue;

}

}

}

return true;

}

void DanChun::FindCB(){

int i,j;

for(i=0; i

for(j=0;j

if(A[i][j]==1){

if(FindE(i,j)==true){ //如果是单位列,怎选择为其对应的价值系数

CB[i]=C[j];

XB[i]=j;

break;

}

}

}

}

}

/*------------------------割平面法------------------------------------*/

void DanChun::Setinit(int m1, int n1, double a[][120],double b[]){ //将值传入int i,j;

m = m1;

n = n1;

//约束系数

for(i=0; i

for(j=0;j

if(j

A[i][j] = a[i][j];

} else {

A[i][j]=0;

if(j==n+i){

A[i][j]=1;

}

}

}

}

for(i=0;i

B[i] = b[i];

CB[i]=0;

}

for(i=0;i

if(i

C[i] = C1[i];

C[i] = M;

}

X[i]=0;

}

}

void DanChun::Reback(){

int i,j;

//XZ[100]; 得到当前最优解

//以及 xi 的值

XZ[0] = favl;

for(i=0;i

XZ[i+1]= X[i];

}

//得到想x系数的矩阵A

for(i=0; i

for(j=0;j

RA[i][j] = A[i][j];

}

}

}

void DanChun::Buffer(double b,int k){ int i,j;

double X[100];

Reback();

//对应的第k行向下取整

for(i=0; i

X[i] = floor(RA[k][i]);

}

//将X[i]中的值加到原来的约束中,即增加一行for(i=0; i

A1[m][i] = X[i] - RA[k][i];

}

//相应的b的系数增加一个

B1[m] = b;

//增加一行

int m1 = m + 1;

//增加一列

int n1 = n + 1;

double s = 0,t =0;

for(i=0; i

if(i==(n-m)){

s = C1[i];

C1[i] = 0;

for(j=i+1; j< n1; j++){

C1[j] = s;

t = C1[j];

s = t;

}

}

for(j=n-1; j>=n-m;j--){

for(i=0; i

A1[i][j+1] = A1[i][j];

}

}

for(i=0; i

if(i

A1[i][n-m] = 0;

}else{

A1[i][n-m] = 1;

}

}

Setinit(m1,n1,A1,B1);

FindCB();

Display();

Com_DC();

}

void DanChun::start(){

init();

FindCB();

Display();

Com_DC();

Gepingmianfa();

}

void DanChun::Gepingmianfa(){

int i=0,j=0;

bool b;

double XZ1[100]; //得到XZ中的值(max z ,xi)

double eps = 0.000001;

double Fb; //向下取整floor得到的值

for(i = 0; i

XZ1[i] = XZ[i];

}

i = 0;

int q = m;

while(i

//if(Xlocation[i] - floor(Xlocation[i]) > eps){

if(X[i] - floor(X[i]) > eps){

Fb = floor(X[i]);

Fb = Fb - X[i];

Buffer(Fb,i);

b = panduan(X);

}else{

b=false;

if(i==q-1){

b = true;

}

}

if(b){

cout<<"此时有最优解!"<

break;

}

i++;

}

}

bool DanChun::panduan(double x[]){

int i;

bool b;

double eps = 0.000001;

for(i=0;i

if(x[i] - floor(x[i]) > eps && (ceil(x[i]) - x[i]) > eps ){

b = false;

return b;

}else {

b = true;

}

}

return b;

}

void main(){

DanChun D;

D.start();

}

相关文档
最新文档