输出结果包含过程的单纯形算法C++程序

为什么写这个程序?
由于在完成单纯形算法的作业时,那么多数,对于粗心的我来说,很容易做错。网上又没找到输出带过程的程序,所以只好花点时间自己写一个。
先说一下前提:一定要先转化成初始的单纯形表,右端向量都大于等于0,并且有一个初始可行基,初始单纯形表示我们的输入。单纯形表的行数包括检验数行,列数包括右端向量,各行数据要先行后列,单纯形表的行的变量的下标要按顺序给出,列也一样。
注:程序的输出不是很美观,但这不是大问题
其他算法的计算可以看我的另一个博文:山东大学软件学院最优化考试复习笔记
先看下面的一个例子
在这里插入图片描述
在这里插入图片描述
初始单纯性表
在这里插入图片描述
继续算

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
进基是按照最大检验数规则和最小下标原则。
输出的第一个表是输入的初始单纯形表
在这里插入图片描述

#include <iostream>
using namespace std;

int row, column; // row是初始单纯形表的行数,column是初始单纯形表的列数

struct Fraction // 分数
{
	int up, down = 1; // 分子,分母
}; 

Fraction table[50][50]; // 单纯形表

int answer[51]; // 表的行的变量下标
int head[51]; // 表的列的变量下标

int inBase(); // 返回进基变量下标
int outBase(int); // 返回出基变量下标
void showTable(); // 显示当前单纯形表
Fraction reduction(Fraction); // 化简分数
Fraction add(Fraction, Fraction); // 分数相加
Fraction minu(Fraction, Fraction); // 分数相减
Fraction multi(Fraction, Fraction); // 分数相乘
Fraction divide(Fraction, Fraction); // 分数相除
int abs(int); // 返回绝对值
int gcd(int, int); // 返回最大公约数

int main()
{
	cout << "请先做出初始单纯性表并满足下面2个要求:" << endl;
	cout << "	1.右端项都大于等于0\n	2.有初始可行基" << endl << endl;
	// 处理输入
	cout << "请输入初始单纯形表的行数(包括检验数行):" << endl;
	cin >> row;
	cout << "请输入初始单纯形表的列数(包括右端向量):" << endl;
	cin >> column;
	cout << "请输入初始单纯形表各行数据(先行后列):" << endl;
	for (int i = 1; i <= row; i++)
	{
		for (int j = 1; j <= column; j++)
		{
			cin >> table[i][j].up;
		}
	}
	cout << "请输入初始单纯形表的行的变量下标" << endl;
	for (int i = 2; i <= row; i++)
		cin >> answer[i];
    cout << "请输入初始单纯形表的列的变量下标" << endl;
    for (int i = 1; i <= column-1; i++)
		cin >> head[i];
	cout << "==============================" << endl;
	showTable();
	cout << endl;
	
	int inVar = inBase(); // 计算进基变量
	int outVar; // 出基变量
	int isOk = 0; // 判断是否已经结束,0未结束,1找到最优解,2问题无界
	while (!isOk)
	{
		if (inVar == 0)
		{
			// 满足最优性准则,此时为最优解,停止
			isOk = 1;
		}
		else
		{
			outVar = outBase(inVar); // 计算出基变量
			if (outVar == 0)
			{
				// 此时问题无界,停止
				isOk = 2;
			}
		}
		
		if (!isOk)
		{
			// 按照算法进行操作
			Fraction temp = table[outVar][inVar];
			for (int j = 1; j <= column; j++)
				table[outVar][j] = divide(table[outVar][j], temp);
				
			for (int i = 1; i <= row; i++)
			{
				if (i == outVar)
					continue;
				else
				{
					temp = table[i][inVar];
					temp.up = -temp.up;
					for (int j = 1; j <= column; j++)
						table[i][j] = add(multi(temp, table[outVar][j]), table[i][j]);
				}
			}
			answer[outVar] = inVar;
			showTable();
			inVar = inBase();
			cout << endl;
		}
	}
	
	if (isOk == 1)
	{
		cout << "成功找到最优解!" << endl;
		cout << "最优解x:自己看" << endl;
		cout << "最优值fmin = ";
		if (table[1][column].down == 1)
			cout << table[1][column].up << endl;
		else
			cout << table[1][column].up << "/" << table[1][column].down << endl;
	}
	else
	{
		cout << "问题无界!" << endl;
	}
	
	return 0;
}

int inBase()
{
	// 选择进基变量
	// 进基变量按最大检验数规则和最小下标原则
	int result = 0; // 保存最大变量的下标
	for (int j = 1; j <= column-1; j++)
	{
		if (table[1][j].up > 0)
		{
			if (result == 0)
				result = j;
			else if (minu(table[1][j], table[1][result]).up > 0)
				result = j;
		}
	}
	return result;
}

int outBase(int num)
{
	// 选择出基变量(num是出基变量所在的列,也是进基变量所在的列)
	// 出基变量根据最小比值测试结果和最小下标原则
	int result = 0; // 保存最小比值测试中最小的下标
	Fraction temp[column+1]; // 保存计算结果
	for (int i = 2; i <= row; i++)
	{
		if (table[i][num].up > 0)
		{
			if (result == 0)
				result = i;
			temp[i] = divide(table[i][column], table[i][num]);
			if (minu(temp[i], temp[result]).up < 0)
				result = i;
		}
	}
	return result;
}

void showTable()
{
	// 输出结果
	cout << "    ";
	for (int i = 1; i <= column-1; i++)
		cout << "x" << head[i] << "   ";
	cout << endl;
	cout << "    ";
	for (int j = 1; j <= column; j++)
	{
		if (table[1][j].down == 1)
			cout << table[1][j].up << "   ";
		else
			cout << table[1][j].up << "/" << table[1][j].down << "  ";
	}
	cout << endl;
	for (int i = 2; i <= row; i++)
	{
		cout << "x" << answer[i] << "  ";
		for (int j = 1; j <= column; j++)
		{
			if (table[i][j].down == 1)
				cout << table[i][j].up << "   ";
			else
				cout << table[i][j].up << "/" << table[i][j].down << "  ";
		}
		cout << endl;
	}
}

Fraction reduction(Fraction result)
{
	// 化简分数
	// 1. 使down为非负数。如果分数为负,那么令分子up为负即可
	// 2. 如果该分数恰为0,那么规定其分子为0,分母为1
	// 3. 分子和分母没有除了1以外的公约数
	if (result.down < 0)
	{
		// 如果分母为负数,那么令分子和分母都为相反数
		result.up = -result.up;
		result.down = -result.down;
	}
	
	if (result.up == 0)
	{
		result.down = 1;
	}
	else
	{
		int d = gcd(abs(result.up), abs(result.down));
		result.up /= d;
		result.down /= d;
	}

	return result;
}

Fraction add(Fraction f1, Fraction f2)
{
	// 分数加法,返回最简负数
	Fraction result;
	result.up = f1.up * f2.down + f2.up * f1.down;
	result.down = f1.down * f2.down;
	return reduction(result);
}

Fraction minu(Fraction f1, Fraction f2)
{
	// 分数减法,返回最简分数
	Fraction result;
	result.up = f1.up * f2.down - f2.up * f1.down;
	result.down = f1.down * f2.down;
	return reduction(result);
}

Fraction multi(Fraction f1, Fraction f2)
{
	// 分数乘法,返回最简分数
	Fraction result;
	result.up = f1.up * f2.up;
	result.down = f1.down * f2.down;
	return reduction(result);
}

Fraction divide(Fraction f1, Fraction f2)
{
	// 分数除法,返回最简分数
	Fraction result;
	result.up = f1.up * f2.down;
	result.down = f1.down * f2.up;
	return reduction(result);
}

int gcd(int a, int b)
{
	return !b ? a : gcd(b, a%b);
}

int abs(int a)
{
	if (a < 0)
		return -a;
	else
		return a;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值