运输问题基本解 最小元素法

关于运输问题的理解这里就不在赘述了,百度上一搜就有很多介绍。

直接进入正题,怎么把算法写出来。这里只考虑运输平衡的运输问题,对应运输不平衡的问题先转换为运输平衡的问题然后解决。

最小元素法需要画一张表,表行标题是对应发货地,列标题是对应收货地点,另外多加一行对应每个收货地的收货量,多加一列对应每个发货地的发货量。

每个格子里有两个数,一个是已知的这个发货地给对应收货地点发货的费用单价dij,另外一个是要求的发货量xij。


收货地1
收货地2
收货地3
收货地4
总发货量
发货1
单位运价为 9
18
1
9
9
发货2
11
6
8
18
10
发货3
14
12
2
16
6
总收货量
4
9
7
5
供需平衡
都是25

最小元素法的思想是找到运价最低的一个地方,优先给那里发货。就这么简单

输入:sNum,Rnum, 行数和列数

s[] , r[]总发货量和总收货量

d[][]单位费用数组

输出:

x[] []最后的结果


算法用到辅助变量ok[][]  这个地方已经确定发货量,初始都是0

算法:1)、如果R[j] = 0, 那么ok[k][j] = 1;k = 1, 2, sNum;

如果S[i] = 0, 那么ok[i][k] = 1;k = 1,2,rNum;

2)、如果所有ok[][]都是1 那么Ok计算结束

3)、遍历d[][];找到没有Ok地方里面最小费用的那个行位置和列位置 i, j;

4)、得X[I][J] = min(S[i],  R[j]);

S[i] -= X[i][j];

R[j] -= X[i][j];

5)、转1)重新执行。


下面给出代码

typedef std::vector<double> VecDoubleType;
typedef std::vector<bool> VecBoolType;
const double g_dTol = 1.0E-3;


	/**********************************
	*vecS		
	*vecE		
	*vecD		 
	*vecX		最后结果,
	***********************************/
	static void Cal(VecDoubleType vecS, VecDoubleType vecR
		, const VecDoubleType &vecD, VecDoubleType &vecX)
	{
		const VecDoubleType::size_type iSSize = vecS.size(), iRSize = vecR.size(), iDSize = vecD.size();
		assert(iSSize * iRSize == iDSize);

		vecX.clear();
		VecBoolType vecOk;
		// 初始化
		VecDoubleType::size_type i = 0, j = 0;
		for (i = 0; i != iDSize; i++)
		{
			vecOk.push_back(false);
			vecX.push_back(0.0);
		}
		
		while(true)
		{
			CheakOk(vecS, vecR, vecOk);
			if (AllOk(vecOk))
			{
				break;
			}
			// 找到最小的距离
			VecDoubleType::size_type iMin = iSSize, jMin = iRSize;
			double dMinDis = 1.0E7;
			for (i = 0; i != iSSize; i++)
			{
				for (j = 0; j != iRSize; j++)
				{
					if (!vecOk[i * iRSize +j])
					{
						if (vecD[i * iRSize + j] - dMinDis < g_dTol)
						{
							iMin = i;
							jMin = j;
							dMinDis = vecD[i * iRSize + j];
						}
					}
				}
			}
			assert(iMin != iSSize && jMin != iRSize);
			double dMinItem  = min(vecS[iMin], vecR[jMin]);
			vecX[iMin * iRSize + jMin] = dMinItem;
			vecS[iMin] -= dMinItem;
			vecR[jMin] -= dMinItem;
			vecOk[iMin * iRSize + jMin] = true;
		}




		std::vector<VecDoubleType>::size_type iDIndex = 0;
		
		
	}
	static bool AllOk(const VecBoolType &vecOk)
	{
		bool bAllOk = true;
		VecBoolType::size_type iBoolSize = vecOk.size(), i = 0;
		for (i = 0; i != iBoolSize; i++)
		{
			if (!vecOk[i])
			{
				bAllOk = false;
				break;
			}
		}
		return bAllOk;
	}

	static void CheakOk(const VecDoubleType &vecS, const VecDoubleType &vecR, VecBoolType &vecOk)
	{
		const VecDoubleType::size_type iSSize = vecS.size(), iRSize = vecR.size();
		VecDoubleType::size_type i = 0, j = 0;
		// 如果这个发送点的发送量已经为0了,那么这一行都Ok
		for (i = 0; i != iSSize; i++)
		{
			if (vecS[i] < g_dTol)
			{
				for (j = 0; j != iRSize; j++)
				{
					vecOk[i * iRSize + j] = true;
				}
			}
		}
		// 如果这个接收点的待接收量减为0了,那么这一列都Ok,
		for (j = 0; j != iRSize; j++)
		{
			if (vecR[j] < g_dTol)
			{
				for (i = 0; i != iSSize; i++)
				{
					vecOk[i * iRSize + j] = true;
				}
			}
		}
	}

测试程序

	VecDoubleType vecS, vecR, vecD, vecX;
	vecS.push_back(9.0);
	vecS.push_back(10.0);
	vecS.push_back(6.0);
	vecR.push_back(4.0);
	vecR.push_back(9.0);
	vecR.push_back(7.0);
	vecR.push_back(5.0);

	vecD.push_back(9.0);
	vecD.push_back(18.0);
	vecD.push_back(1.0);
	vecD.push_back(9.0);

	vecD.push_back(11.0);
	vecD.push_back(6.0);
	vecD.push_back(8.0);
	vecD.push_back(18.0);

	vecD.push_back(14.0);
	vecD.push_back(12.0);
	vecD.push_back(2.0);
	vecD.push_back(16.0);
Cal(vecS, vecR, vecD, vecX);
//		输入:
	//	9	18	1	9		9
	//	11	6	8	18		10
	//	14	12	2	16		6
	//
	//	4	9	7	5
	//
	//     输出为 0,0,7,2,1,9,0,0,3,0,0,3 不是最优,下面的结果 150是最优,
	//	3	0	1	5
	//	1	9	0	0
	//	0	0	6	0
	//	
	//


上面解出的结果不是最优解,只是一个可行解,如果要得到最优解需要继续进行计算,计算方法有位势法和活路法,算法很复杂没有写出来。
但是用另外一种差额法也可以得到基本可行解,而且效果比最小元素法要好。对于上面的列子能直接得到最优解。



  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值