装载问题
有一批共n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i的重量为wi,且
装载问题要求确定是否有一个合理的装载方案可将这个集装箱装上这2艘轮船。如果有,找出一种装载方案。
装载方案。
(1)首先将第一艘轮船尽可能装满;
(2)将剩余的集装箱装上第二艘轮船。
将第一艘轮船尽可能装满等价于选取全体集装箱的一个子集,使该子集中集装箱重量之和最接近。由此可知,装载问题等价于以下特殊的0-1背包问题。
代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 装载问题
{
class Loading
{
static int n; // 集装箱数
static int[] weight; // 集装箱重量数组
static int limitWeight; // 第一艘轮船的载重量
static int currentWeight; // 当前载重量
static int bestWeight; // 当前最优载重量
static int remainWeight; // 剩余集装箱重量
static int[] x; // 当前解
static int[] bestx; // 当前最优解
/// <summary>
/// 使用回溯法求解装载问题,调用递归方法backtrack(0)实现回溯搜索。
/// </summary>
/// <param name="weightArray">重量数组</param>
/// <param name="c1Weight">轮船c1的载重量</param>
/// <param name="_x">[返回]最优解</param>
/// <returns>返回不超过c1Weight的最大子集和</returns>
public static int maxLoading(int[] weightArray, int c1Weight, out int[] _x)
{
/* 初始化数据成员 */
n = weightArray.Length - 1;
weight = weightArray;
limitWeight = c1Weight;
currentWeight = 0;
bestWeight = 0;
x = new int[n + 1];
_x = new int[n + 1];
bestx = _x;
/* 初始化剩余集装箱的重量 */
foreach(int elem in weight)
{
remainWeight += elem;
}
/* 计算最优载重量 */
backtrack(0);
return bestWeight;
}
/// <summary>
/// 搜索子集树的第i层子树
/// </summary>
/// <param name="i"></param>
private static void backtrack(int i)
{
if (i > n) {
if (currentWeight > bestWeight) {
x.CopyTo(bestx, 0);
bestWeight = currentWeight;
}
return;
}
remainWeight -= weight[i];
if (currentWeight + weight[i] <= limitWeight) {
x[i] = 1;
currentWeight += weight[i];
backtrack(i + 1);
currentWeight -= weight[i];
}
if (currentWeight + remainWeight > bestWeight) {
x[i] = 0;
backtrack(i + 1);
}
remainWeight += weight[i];
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 装载问题
{
class Program
{
static void Main(string[] args)
{
// 集装箱重量数组
int[] w = new int[] {10, 40, 40, 23, 41, 12, 6, 78, 44, 154 };
int c1 = 250;
int c2 = 200;
int[] x;
int bestc1 = Loading.maxLoading(w, c1, out x);
int weight = 0;
foreach(int elem in w)
{
weight += elem;
}
if (c2 < weight - bestc1)
{
Console.WriteLine("无解。");
return;
}
Console.WriteLine("c1可装载{0}", bestc1);
Console.WriteLine("c1包含集装箱:");
for(int i=0; i<x.Length; i++)
{
if (x[i] == 1)
{
Console.Write("{0} ", i + 1);
}
}
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("c2可装载{0}", weight - bestc1);
Console.WriteLine("c2包含集装箱:");
for (int i = 0; i < x.Length; i++)
{
if (x[i] == 0)
{
Console.Write("{0} ", i + 1);
}
}
Console.WriteLine();
}
}
}