0-1 背包问题的扩展
问题提出:
给定 n种物品和一背包, 物品的重量是 wi, 体积为 bi, 价值为 vi, 背包的容量为 C, 容积为 D, 问应如何选择装入背包中的物品, 使得装入背包中物品的总价值最大? 在选择装入背包的物品时, 对每种物品 i 只有两种选择, 即装入背包或不装入背包。不能将物品 i 装入背包多次, 也不能只装入部分物品 i。
算法分析:
代码实现:
1

/**//* 0-背包问题扩展2
* By Flouse@2008年12月9日 17时06分28秒3
*/4
using System;5
using System.Collections.Generic;6
using System.Text;7

8
namespace YourNameSpace // 修改为统一的命名空间9


{10

/**//// <summary>装车类</summary>11
public class Loading12

{13

/**//// <summary>货车载重量(t)</summary>14
private int capacity;15

/**//// <summary>货车体积容量(m3)</summary>16
private int cubage;17

/**//// <summary>最优(运费最高)装载清单</summary>18
private List<string> optimizedBills = new List<string>();19
public float totalPrice;20

21

/**//// <summary>运单信息(装载相关)</summary>22
public struct TranBill23

{24

/**//// <summary>托运单号</summary>25
public string tranID;26

/**//// <summary>拆单号</summary>27
public int tranSplitID;28

/**//// <summary>重量(t),实际运算里四舍五入化整</summary>29
public float billWeight;30

/**//// <summary>体积(m3),实际运算里四舍五入化整</summary>31
public float billVolumn;32

/**//// <summary>运费</summary>33
public float tranPrice;34
};35

36

/**//// <summary>初始化货车信息</summary>37
/// <param name="capacity">货车载重量(t)</param>38
/// <param name="cubage">货车体积容量(m3)</param>39
Loading(int capacity, int cubage)40

{41
this.capacity = capacity;42
this.cubage = cubage;43
}44
~Loading()45

{46
GC.Collect();47
//?? 释放内存48
}49

/**//// <summary>求解最优装车方案</summary>50
/// <param name="tbs">待运的托运单</param>51
/// <param name="mode">重量、体积转整模式52
/// <value>0.0f~1.0f, 当 mode = 0.5f 时,即为四舍五入方式;当 mode = 0.0f 时, 即为最贪婪方式;当 mode = 1.0f 时,即为最保险方式</value>53
/// <example>(int)(billWeight + mode), (int)(billVolumn + mode)</example>54
/// </param>55
/// <returns></returns>56
public List<string> doLoad(TranBill[] tbs, float mode)57

{58
int count = tbs.Length;59
int[] w = new int[count + 1];60
int[] v = new int[count + 1];61
float[] p = new float[count + 1];62
float[, ,] m = new float[count + 1, capacity + 1, cubage + 1];63
for (int i = 1; i <= count; i++)64

{65
w[i] = (int)(tbs[i - 1].billWeight + mode);66
v[i] = (int)(tbs[i - 1].billVolumn + mode);67
p[i] = tbs[i - 1].tranPrice;68
}69
Knapsack(p, w, v, count, m);70
Trackback(m, w, v, tbs);71
return optimizedBills;72
}73

74
private void Trackback(float[, ,] m, int[] w, int[] v, TranBill[] tbs)75

{76
int _capacity = capacity, _cubage = cubage, n = tbs.Length;77
optimizedBills.Clear();78
for (int i = 1; i < n; i++)79

{80
if (m[i, _capacity, _cubage] - m[i + 1, _capacity, _cubage] > 0.000001f)81

{82
optimizedBills.Add(tbs[i - 1].tranID + '.' + tbs[i-1].tranSplitID);83
_capacity -= w[i];84
_cubage -= v[i];85
}86
}87
if (m[n, _capacity, _cubage] > 0) optimizedBills.Add(tbs[n - 1].tranID + '.' + tbs[n - 1].tranSplitID);88
}89

90

/**//// <summary>采用动态规划标记法(0-1背包问题算法)</summary>91
/// <param name="p"></param>92
/// <param name="w"></param>93
/// <param name="v"></param>94
/// <param name="n"></param>95
/// <param name="m"></param>96
private void Knapsack(float[] p, int[] w, int[] v, int n, float[, ,] m)97

{98
int wMax = Math.Min(w[n] - 1, capacity);99
int vMax = Math.Min(v[n] - 1, cubage);100

101
int i, j, k;102

103
for (i = 0, j = 0; i <= wMax; i++)104
for (j = 0; j < cubage; j++)105
m[n, i, j] = 0;106
for (j = 0; j <= vMax; j++)107
for (i = wMax+1; i < capacity; i++)108
m[n, i, j] = 0;109

110
for (i = w[n]; i <= capacity; i++)111
for (j = v[n]; j <= cubage; j++)112
m[n, i, j] = p[n];113

114
for (k = n - 1; k > 1; k--)115

{116
wMax = Math.Min(w[k] - 1, capacity);117
vMax = Math.Min(v[k] - 1, cubage);118

119
for (i = 0, j = 0; i <= wMax; i++)120
for (j = 0; j < cubage; j++)121
m[k, i, j] = m[k + 1, i, j];122
for (j = 0; j <= vMax; j++)123
for (i = wMax+1; i < capacity; i++)124
m[k, i, j] = m[k + 1, i, j];125

126
for (i = w[k]; i <= capacity; i++)127
for (j = v[k]; j <= cubage; j++)128
m[k, i, j] = Math.Max(m[k + 1, i, j], m[k + 1, i - w[k], j - v[k]] + p[k]);129
}130
m[1, capacity, cubage] = m[2, capacity, cubage];131
if (capacity >= w[1] && cubage >= v[1]) m[1, capacity, cubage] = Math.Max(m[1, capacity, cubage], m[2, capacity - w[1], cubage - v[1]] + p[1]);132

133
totalPrice = m[1, capacity, cubage];134
}135

136
// 回溯法,示实现137
//class BackBag{138
//public:139
// BackBag(int W){140
// maxW = W;141
// ac = maxValue = nowValue = 0;142
// }143
// void KnapSack(int v[], int c[], bool used[], int n){ //回溯法144
// for (int i = 0; i < n; i++){145
// nowValue += v[i];146
// ac += c[i];147
// used[i] = true;148
// }149
// search(0, v, c, used, n);150
// }151
// void search(int i, int v[], int c[], bool used[], int n){152
// if (i==n) return;153
// if (nowValue <= maxValue) return;154
// if (ac <= maxW){155
// maxValue = nowValue;156
// return;157
// } 158
// nowValue -= v[i]; 159
// ac -= c[i];160
// used[i] = false;161
// search(i+1, v, c, used, n); //考虑不取i162
// nowValue += v[i];163
// ac += c[i];164
// used[i] = true;165
// search(i+1, v, c, used, n); //考虑取i166
// }167
// int getMaxV(){168
// return maxValue;169
// }170
//private:171
// int maxW; //背包所能承受的重量172
// int ac;173
// int maxValue;174
// int nowValue;175
//};176

177

/**//// <summary>调用示例</summary>178
/// <param name="args"></param>179
static void Main(string[] args)180

{181
Loading l = new Loading(5, 5); // 设置货车的重容和体容182

183
int n = Convert.ToInt32(Console.ReadLine());184
TranBill[] tranBills = new TranBill[n];185
string inStream;186
for (int i = 0; i < n; i++)187

{188
inStream = Console.ReadLine();189
string[] temp = inStream.Split('\t');190
tranBills[i].tranID = temp[0];191
tranBills[i].tranSplitID = int.Parse(temp[1]);192
tranBills[i].billWeight = float.Parse(temp[2]);193
tranBills[i].billVolumn = float.Parse(temp[3]);194
tranBills[i].tranPrice = float.Parse(temp[4]);195
}196
List<string> optimizedBills = l.doLoad(tranBills, 0.5f); // 执行最优装载求解197
Console.WriteLine(l.totalPrice); // 最大托运费198
foreach (string s in optimizedBills) // 装载序列199

{200
Console.Write(s + '\t');201
}202
}203
}204
}205

206

/**//* 示例输入207
5208
tran 1 1 1 100209
tran 2 1 1 100210
tran 3 1 1 100211
tran 4 1 1 100212
tran 5 1 1 100213
*/
浙公网安备 33010602011771号