线性规划专题——SIMPLEX 单纯形算法(四)——实现

版权声明:本文为博主jmh原创文章,未经博主允许不得转载。 https://blog.csdn.net/jmh1996/article/details/85047305

实现的原理见:
线性规划专题——SIMPLEX 单纯形算法(一)
线性规划专题——SIMPLEX 单纯形算法(二)
线性规划专题——SIMPLEX 单纯形算法(三)——示例、注意点

实现过程

重点是实现PIVOT 指定主元的高斯约旦消元,以及INITICIALSIMPLEX初始化SIMPLEX,注意 在实现中,本人并没有构造辅助线性规划,因为看起来比较麻烦。

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <vector>
#include <algorithm>
#include <set>
#include <iostream>
using namespace std;
#define N (202)
#define INFTY (1e30)
#define EXP (1e-10)
//INFIY 正无穷
//EXP	无穷小量,主要为了对付double 在判断时可能出现误差
double co_matrix[N][N] = { 0 };
double b_matrix[N]= { 0 };
double c_matrix[N] = { 0 };
set<int> BI;//存储基本列的下标
double z;//存储最小值
double theta[N] = { 0 };
double lambda[N] = { 0 };
int INITLIZESIMPLEX(int m,int n);
vector<double > CALCULATEX(int m,int n);
void PIVOT(int i,int j,int m,int n);//以co_matrix的aij为主元,执行一次高斯约旦消元
int find_min_index(double * vec,int len)
{
	double tmp = vec[0];
	int index = 0;
	for (int i = 0; i < len; i++)
	{
		if (tmp>vec[i])
		{
			tmp = vec[i], index = i;//选第1个最小的
		}
	}
	return index;
}
int find_max_index(double * vec, int len)
{
	double tmp = vec[0];
	int index = 0;
	for (int i = 0; i < len; i++)
	{
		if (tmp<vec[i])
		{
			tmp = vec[i], index = i;//选第1个最大的
		}
	}
	return index;
}
pair < vector<double>, double > SIMPLEX(int m, int n, int init_flag = 0)
{
	vector<double> x;
	int feasible = INITLIZESIMPLEX(m, n);//可能有解的时候
	while (feasible)
	{
		int min_ci = find_min_index(c_matrix, n);
		if (c_matrix[min_ci] >= 0)
			//所有的ci都大于0,说明目标函数已经收敛了 找到了最优值
		{
			x = CALCULATEX(m,n);
			break;
		}
		//针对第min_ci列 计算最小的非负theta
		for (int i = 0; i < m; i++)
		{
			if (co_matrix[i][min_ci]>0)
				//这样计算的theta才是非负的
			{
				theta[i] = b_matrix[i] / co_matrix[i][min_ci];
			}
			else
				//当co_matrix[i][min_ci]为0,或者为负的时候,都不用去考虑
			{
				theta[i] = INFINITY;
			}
		}
		int max_thetai = find_min_index(theta, m);
		if (abs(theta[max_thetai] - INFTY) < EXP)
		{
			x.clear();
			z = INFTY;
			printf("unbounded");
			break;
		}
		PIVOT(max_thetai, min_ci,m,n);//做一次高斯消元
	}
	return pair<vector<double> ,double> (x, -z);
}
int INITLIZESIMPLEX(int m,int n)
{
	int min_bi = find_min_index(b_matrix, m);//找到bi最小的那个

	BI.clear();
	for (int i = m; i < n; i++)
	{
		BI.insert(i);
	}

	if (b_matrix[min_bi] >= 0)
		//左右的b都是非负的,那么这个问题就可以自然的获取一组顶点和解
	{
		return 1;
	}
	//使用黑科技,直接从bi最小的那一行 任选一个 小于0 的co_matrix[i]来操作
	//并没有构建辅助线性规划,因为太麻烦了
	int col_index = -1;
	for (int i = 0; i < n; i++)
	{
		if (co_matrix[min_bi][i] < 0)
		{
			col_index = i;
			break;
		}
	}
	if (col_index == -1)
	{
		BI.clear();
		printf("Infeasible");
		return 0;//无解
	}
	//否则执行一次转轴操作
	PIVOT(min_bi, col_index,m,n);
	return 1;
}
vector<double > CALCULATEX(int m,int n)
{
	vector<double> x;
	for (int i = 0; i < n; i++)
	{
		x.push_back(0);
	}
	for (auto it = BI.begin(); it != BI.end();it++)
	{
		int i = *it;
		{
			for (int j = 0; j < m; j++)
			{
				if (abs(co_matrix[j][i] -1 ) < EXP)
				{
					x[i] = b_matrix[j];
					if (x[i] < 0)
					{
						x.clear();
						printf("Infeasible");
						break;
						//无解
					}
				}
			}
		}
	}
	return x;
}
void PIVOT(int row, int col,int m,int n)
{
	//基的变换
	for (auto it = BI.begin(); it != BI.end(); it++)
		//从已有的基里面找到那个需要被替换出去的基
	{
		if (abs(co_matrix[row][*it] - 1) < EXP)
		{
			BI.erase(*it);
			break;
		}
	}
	BI.insert(col);

	//系数矩阵的高斯约旦消元
	for (int i = 0; i < n; i++)
		//把当前行除以co_matrix[row][col]
	{
		if (i != col)
		{
			co_matrix[row][i] /= co_matrix[row][col];
		}
	}
	b_matrix[row] /= co_matrix[row][col];
	co_matrix[row][col] = 1;

	//把其他行 减去第row行,校区第row行的第col个元素,以及b_matrix的高斯约旦
	for (int i = 0; i < m; i++)
	{
		if (i != row)
		{
			double factor = co_matrix[i][col] / co_matrix[row][col];
			for (int j = 0; j < n; j++)
			{
				co_matrix[i][j] -= co_matrix[row][j] * factor;
			}
			b_matrix[i] -= b_matrix[row] * factor;
		}
	}
	//c_matrix的高斯约旦
	double factor = c_matrix[col] / co_matrix[row][col];
	for (int j = 0; j < n; j++)
	{
		c_matrix[j] -= co_matrix[row][j] * factor;
	}
	//z的变换
	z -= b_matrix[row] * factor;



}
int main()
{
	//TEST 1.
	/*int m = 4, n = 7;
	co_matrix[0][0] = 1, co_matrix[0][1] = 1, co_matrix[0][2] = 1, co_matrix[0][3] = 1, co_matrix[0][4] = 0, co_matrix[0][5] = 0, co_matrix[0][6] = 0;
	co_matrix[1][0] = 1, co_matrix[1][1] = 0, co_matrix[1][2] = 0, co_matrix[1][3] = 0, co_matrix[1][4] = 1, co_matrix[1][5] = 0, co_matrix[1][6] = 0;
	co_matrix[2][0] = 0, co_matrix[2][1] = 0, co_matrix[2][2] = 1, co_matrix[2][3] = 0, co_matrix[2][4] = 0, co_matrix[2][5] = 1, co_matrix[2][6] = 0;
	co_matrix[3][0] = 0, co_matrix[3][1] = 3, co_matrix[3][2] = 1, co_matrix[3][3] = 0, co_matrix[3][4] = 0, co_matrix[3][5] = 0, co_matrix[3][6] = 1;
	b_matrix[0] = 4, b_matrix[1] = 2, b_matrix[2] = 3, b_matrix[3] = 6;
	c_matrix[0] = -1, c_matrix[1] = -14, c_matrix[2] = -6, c_matrix[3]= 0, c_matrix[4]= 0, c_matrix[5] = 0, c_matrix[6] = 0;*/

	//TEST 2.
	/*int m = 2, n = 4;
	co_matrix[0][0] = -1, co_matrix[0][1] = -1, co_matrix[0][2] = 1, co_matrix[0][3] = 0;
	co_matrix[1][0] = 1, co_matrix[1][1] = 1, co_matrix[1][2] = 0, co_matrix[1][3] = 1;
	b_matrix[0] = -1, b_matrix[1] = 2;
	c_matrix[0] = 1, c_matrix[1]= 2, c_matrix[2] = 0, c_matrix[3]= 0;
	*/
	//TEST 3.无解
	int m = 2, n = 4;
	co_matrix[0][0] = -1, co_matrix[0][1] = -1, co_matrix[0][2] = 1, co_matrix[0][3] = 0;
	co_matrix[1][0] = 1, co_matrix[1][1] = 1, co_matrix[1][2] = 0, co_matrix[1][3] = 1;
	b_matrix[0] = -2, b_matrix[1] = -1;
	c_matrix[0] = 1, c_matrix[1] = 2, c_matrix[2] = 0, c_matrix[3] = 0;

	auto rst = SIMPLEX(m, n);
	if (rst.first.size())
		printf("min:%0.5f\n", rst.second);

	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jmh1996/article/details/85047305