单纯形法代码求解(含超详细代码注释和整个流程图)

代码的函数实现流程图:
在这里插入图片描述
该过程是以目标函数的最小值作为标准型求解的,即当目标函数需要求解最大值时,先将目标函数取反,然后求取反后函数的最小值即可。

实现代码

#include "pch.h"
#include <iostream>
#include<stdio.h>
#include<stdlib.h>  
#include<string.h>
#include<math.h>
#include<iostream>
using namespace std;

#define M 1000			//大M数
#define zero 0.000001		//作为0的代替
#define maxn 100				//代表数组大小

float matrix[maxn][maxn], x[maxn]; //x为解的数组	  //matrix代表的是系数矩阵(存放约束矩阵中的系数和目标函数的系数)
int a[maxn]; //判断哪些是基变量   0:非基础,1:基础
int m; 		//方程变量数
int n;		//约束条件数
int type;	//求最大最小值的类型,0:最小 1:最大
int Loose_variable; 	//松弛变量数
int Remain_variable;	//剩余变量数
int Artificial_variable;	//人工变量数
int total_variable;		//总变量数
int base[maxn];			//储存基变量的下标
int T = 0;		//用于存放有几个基变量数量
int Duo = 0;			//是否存在多解的标志
int non = 0;	//当non为1的时候代表当前无可行解

void Other_update(int in, int temp) {
	float c = 0;
	for (int i = 0; i <= n; i++) {
		c = matrix[i][in] / matrix[temp][in];

		if (i != temp) {       //除主元素行  对其他行进行处理
			for (int j = 0; j <= total_variable; j++) {
				matrix[i][j] = matrix[i][j] - matrix[temp][j] * c;		//aij-asj/ask·aik→aij   和  bi-bs/ask·aik→bi
			}
		}
	}
}

void Main_update(int in, int temp) {	//temp对应主元素行,in对应主元素列
	for (int i = 0; i <= total_variable; i++) {
		if (i != in) {
			matrix[temp][i] = matrix[temp][i] / matrix[temp][in]; //  bs/ask → bs
		}
	}
	matrix[temp][in] = 1;			//  1→ask
}

int ExchangeOut(int *temp, int in) {		//求换出基
	int i;
	float minn = 10000;
	for (i = 0; i < n; i++) {      //对所有aik>0计算出相关的θ,θ=bi/aik.(实际上就是matrix[i][total_variable] / matrix[i][in])    (k对用着in)
		if (fabs(matrix[i][in]) >= zero && (matrix[i][total_variable] / matrix[i][in] >= 0) && minn > matrix[i][total_variable] / matrix[i][in]) {
			minn = matrix[i][total_variable] / matrix[i][in];
			*temp = i;
		}
	}

	for (i = 0; i < total_variable; i++) {
		if (a[i] == 1 && matrix[*temp][i] == 1)
			return i;			//返回换出变量的下标(前提是这个变量之前为基变量)
	}
}

int Is_unbounded(int in) {   //进行无界解的判定
	float maxx = -1;
	for (int i = 0; i < n; i++) {
		if (fabs(matrix[i][in]) >= zero && maxx < matrix[i][total_variable] / matrix[i][in]) {
			maxx = matrix[i][total_variable] / matrix[i][in];
		}
	}
	if (maxx < 0)  return 1;
	return 0;
}

void FinalResult() {	//输出最终结果
	if (type == 0) printf("\n目标函数最小值为: %f", -matrix[n][total_variable]);
	else printf("\n目标函数最大值为: %f,  ", matrix[n][total_variable]);
	cout << "对应的基可行解为:(";
	for (int i = 0; i < total_variable - 1; i++) {
		printf("%.2f,", x[i]);
	}
	printf("%.2f)\n", x[total_variable - 1]);
	
	cout << "原问题的解向量为:(";
	for (int i = 0; i < m - 1; i++) {
		printf("%.2f,", x[i]);
	}
	printf("%.2f)\n", x[m - 1]);
}

int Duojie() {			//非基变量检验数的判定
	for (int i = 0; i < total_variable; i++) {			//在非基变量对应的检验数中判定
		int flag = 0;
		for (int j = 0; j < T; j++) {
			if (i + 1 == base[j]) {			//代表对应着基变量
				flag = 1;
				break;
			}
		}

		if (!flag) {			//对非基变量的检验数进行处理
			if (fabs(matrix[n][i]) <= zero) {		//认为存在为0的情况
				printf("存在无穷多个最优解\n");
				Duo = 1;
				return 0;
			}
		}
	}
	return 0;
}

void Is_solution() {
	for (int i = m + Loose_variable + Remain_variable; i < total_variable; i++) {
		if (fabs(x[i]) >= zero) {     //代表基变量中存在非零的人工变量
			printf("该问题无可行解\n");			//无可行解
			non = 1;
			return;
		}
	}
}

int Min_test() {        //求出最小检验数的下标
	int temp = 0;
	float min = matrix[n][0];
	for (int i = 1; i < total_variable; i++) {
		if (min > matrix[n][i]) {
			min = matrix[n][i];
			temp = i;
		}
	}
	return temp;
}

int test_number() {		//所有检验数与0比较
	for (int i = 0; i < total_variable; i++) {
		if (fabs(matrix[n][i]) >= zero) {
			if (matrix[n][i] < 0)
				return 0;
		}
	}
	return 1;
}

void iteration_Result() {		//输出每次迭代结果
	cout << endl;
	for (int i = 0; i < total_variable; i++) {
		printf("          X%d", i + 1);
	}
	cout << "	(该过程对应的解向量)";
	cout << endl;

	cout << "  ";
	for (int i = 0; i < total_variable; i++) {
		printf("%12.2f", x[i]);
	}

	if (type == 1)
		printf("	f(max)=%f\n", matrix[n][total_variable]);
	else printf("	f(min)=%f\n", matrix[n][total_variable]);
}

void Print_factor() {		//输出中间系数和检验数
	memset(base, 0, sizeof(base));			//清除基变量数组
	T = 0;
	int temp = 0;
	cout << "—————————————————————————————————————————————————————\n";
	for (int i = 0; i < n; i++) {
		for (int k = temp; k < total_variable; k++) {
			if (a[k] == 1) {
				printf("X%d ", k + 1);		//输出基变量符号
				base[T++] = k + 1;				//将基变量下标存储到base中
				temp = k + 1;
				k = total_variable;
			}
		}

		for (int j = 0; j <= total_variable; j++) {
			printf("%12.2f", matrix[i][j]);
		}
		cout << endl;
	}

	cout << "δj ";
	for (int j = 0; j <= total_variable; j++) {
		printf("%12.2f", matrix[n][j]);				//此处的值就是检验数Rj
	}
	cout << endl;
}

void Base_solution() {	//求出基变量的值,非基变量设为0
	for (int i = 0; i < n; i++)
		for (int j = 0; j < total_variable; j++)
			if (matrix[i][j] == 1 && a[j] == 1) {   //假如当前某个变量是基变量,在这一行中求出来
				x[j] = matrix[i][total_variable];		//认为非基变量全部置0,则基变量的值等于方程右值
				j = total_variable;
			}
	for (int i = 0; i < total_variable; i++)
		if (a[i] == 0) x[i] = 0;			//非基变量置0
}

void Print_head() {		//打印表头
	cout << "\n\n结果和过程如下所示:" << endl;
	cout << "**************************************************************************************************************" << endl;
	cout << "X";
	for (int i = 1; i <= total_variable; i++)
		printf("          a%d", i);
	printf("          b\n");
}

void Initial_test() {  //计算初始检验数
	if (Artificial_variable != 0) {
		for (int i = m + Loose_variable + Remain_variable; i < total_variable; i++) {
			for (int j = 0; j < n; j++) {
				if (matrix[j][i] == 1) {       //判断哪些约束条件行加上了人工变量
					for (int k = 0; k <= total_variable; k++) {	//此部分为大M法则中的检验数Rj的计算,并存入matrix矩阵中
						matrix[n][k] = matrix[n][k] - matrix[j][k] * M;		//此处的M认为人工变量对应的系数
					}
					j = n;		//跳出当前循环
				}
			}
		}
	}
}

void Initial_base() {	//初始设置基变量,对应下标存在a数组中  将剩余和人工变量初始设为基变量
	int i;
	for (i = 0; i < m + Loose_variable; i++)
		a[i] = 0;
	for (i = m + Loose_variable; i < total_variable; i++)		//初始假定某些变量为基变量(基变量的数量要和约束条件数相同)
		a[i] = 1;					//从m + Loose_variable到s-1对应的x设置为基变量
}

void Merge(float loose[][maxn], float remain[][maxn], float artificial[][maxn], float b[]) {
	int i, j;			//在系数矩阵中先进行对松弛(负数变量)进行合并,再依次向外合并剩余变量和人工变量
	for (i = 0; i < n; i++) {
		for (j = m; j < m + Loose_variable; j++) {
			if (loose[i][j - m] != -1) matrix[i][j] = 0;
			else matrix[i][j] = -1;
		}

		for (j = m + Loose_variable; j < m + Loose_variable + Remain_variable; j++) {
			if (remain[i][j - m - Loose_variable] != 1) matrix[i][j] = 0;
			else matrix[i][j] = 1;
		}

		for (j = m + Loose_variable + Remain_variable; j < total_variable; j++) {
			if (artificial[i][j - m - Loose_variable - Remain_variable] != 1) matrix[i][j] = 0;
			else matrix[i][j] = 1;
		}
		matrix[i][total_variable] = b[i];			//矩阵中每一行最后为方程右值
	}

	//下面为目标函数z系数的设置
	for (i = m; i < m + Loose_variable + Remain_variable; i++)//对松弛变量和剩余变量系数设0
		matrix[n][i] = 0;
	for (i = m + Loose_variable + Remain_variable; i < total_variable; i++)
		matrix[n][i] = M;		//采用的是大M法则,在martix矩阵对应的人工变量处设置一个较大的系数
	matrix[n][total_variable] = 0;
}

void SetZero(float c[][maxn], int row, int vol) {
	for (int i = 0; i < n; i++) {
		if (i != row)
			c[i][vol] = 0;	//确保各类型数组在当前行(row)的vol列为1,其他行(即其他约束行)设置为0
	}
}

void Input(float b[], int expression[]) {     //处理输入的程序
	cout << "方程变量数:" << endl;
	cin >> m;
	cout << "约束条件数:" << endl;
	cin >> n;

	cout << "依次输入约束方程系数、方程右值、等式类型( 0:<= 1:= 2:>=n ):" << endl;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++)
			cin >> matrix[i][j];
		cin >> b[i] >> expression[i];
	}

	cout << "输入目标函数Z中的系数:" << endl; /* 输入z */
	for (int i = 0; i < m; i++)
		cin >> matrix[n][i];			//matrix在第n行储存目标函数中的系数

	cout << "选择求解类型( 0:Min 1:Max ):" << endl; //输入求最大值还是最小值
	do {
		cin >> type;			//type只能选择0或1
		if (type != 0 && type != 1) printf("输入错误!");
	} while (type != 0 && type != 1);

	if (type == 1)		//当目标函数求最大值时
		for (int i = 0; i < m; i++)		//将目标函数Z中的系数求反
			matrix[n][i] = -matrix[n][i];
}

void Normal(float b[], int expression[]) {
	float loose[maxn][maxn];	//松弛变量数组
	float remain[maxn][maxn];	//剩余变量数组
	float artificial[maxn][maxn]; //人工变量数组
	Loose_variable = Remain_variable = Artificial_variable = 0;
	for (int i = 0; i < n; i++) {     //进行约束条件不等式的判定
		if (expression[i] == 0) {      //代表输入符号为小于等于
			remain[i][Remain_variable++] = 1;		//增加一个剩余变量
			SetZero(remain, i, Remain_variable - 1); //确保该列的其余行对应的系数为0
		}

		if (expression[i] == 1) {      //等于
			artificial[i][Artificial_variable++] = 1;		//加上一个人工变量
			SetZero(artificial, i, Artificial_variable - 1);  //确保该列的其余行对应的系数为0
		}

		if (expression[i] == 2) {      //大于等于
			artificial[i][Artificial_variable++] = 1;	//减去一个松弛变量,再加上一个人工变量
			loose[i][Loose_variable++] = -1;
			SetZero(artificial, i, Artificial_variable - 1);
			SetZero(loose, i, Loose_variable - 1);
		}
	}

	total_variable = Loose_variable + Remain_variable + Artificial_variable + m;  //增加的三种变量数和原目标函数变量数(m)构成总变量数
	Merge(loose, remain, artificial, b);		//将增加的变量对应的系数和合并到原矩阵系数中
	Initial_base(); //初始设置基变量,对应下标存在a数组中
	Initial_test(); //计算初始检验数
	Print_head(); //打印表头
}

void Simplex() {            //单纯形法算法
	int in;	//进基变量
	int out; //出基变量
	int temp = 0;

	while (1) {     //循环寻找最优解
		Base_solution(); //求出基础可行解
		Print_factor(); //进行中间结果的打印(系数矩阵)和检验数
		iteration_Result(); //输出解数组  非基变量为0   每次迭代的解和目标函数值
		if (!test_number()) in = Min_test(); //求最小检验数下标,对应着换入基的下标
		else {
			cout << "—————————————————————————————————————————————————————\n";
			if (Artificial_variable != 0) Is_solution();    //判断是否有可行解
			Duojie();   //需要进行多个最优解的判定

			if (!non) {		//当不存在无可行解的情况,则输出最优解。
				if (Duo == 1) {
					FinalResult();	//输出最终结果(最优目标函数值)
				}
				else {		//代表存在唯一解的情况
					cout << "存在唯一最优解" << endl;
					FinalResult();
				}
			}
			cout << "\n**************************************************************************************************************" << endl;
			return;
		}

		if (Is_unbounded(in)) {         //判断无界情况
			cout << "—————————————————————————————————————————————————————\n";
			printf("该问题为无界解\n!");
			cout << "\n**************************************************************************************************************" << endl;
			return;
		}
		out = ExchangeOut(&temp, in); //求出换出基
		Main_update(in, temp);  //主元素行、主元素列更新
		Other_update(in, temp); //对其他行列元素进行更新变换
		swap(a[in], a[out]);   //由于进出的基变量发生了交换,因此储存它们下标的数组a中的值也会发生交换
	}
}

int main() {
	int expression[maxn];//储存输入符号(大于小于等于)
	float b[maxn]; //方程右值

	Input(b, expression);      //将问题进行输入
	Normal(b, expression);     //化为标准型
	Simplex();                 //单纯形法求解过程

	system("pause");
	return 0;
}

案例结果
在这里插入图片描述

在这里插入图片描述

  • 19
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值