代码的函数实现流程图:
该过程是以目标函数的最小值作为标准型求解的,即当目标函数需要求解最大值时,先将目标函数取反,然后求取反后函数的最小值即可。
实现代码
#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;
}
案例结果