假设:物品有20个,每个的重量不一样,且不可分割,现在需要装入到重量为30Kg的背包中。
1、求出最少需要多个背包?
2、每个背包的装的是哪几个物品?
本人才疏学浅,求示例个C#代码~
using System;
using System.Collections.Generic;
namespace KnapsackProblem
{
class Program
{
static void Main(string[] args)
{
// 物品重量数组
int[] weights = new int[] { 2, 3, 4, 5, 9, 7, 8, 10, 1, 6, 11, 12, 14, 15, 16, 18, 19, 20, 21, 22 };
// 背包容量
int capacity = 30;
int[] dp = new int[capacity + 1];
List<List<int>> items = new List<List<int>>();
for (int i = 0; i < dp.Length; i++)
{
items.Add(new List<int>());
}
for (int i = 0; i < weights.Length; i++)
{
for (int j = capacity; j >= weights[i]; j--)
{
if (dp[j] < dp[j - weights[i]] + 1)
{
dp[j] = dp[j - weights[i]] + 1;
items[j].Clear();
items[j].Add(i);
items[j].AddRange(items[j - weights[i]]);
}
}
}
Console.WriteLine($"需要 {dp[capacity]} 个背包");
Console.WriteLine($"每个背包装的物品编号分别为:");
for (int i = 0; i < items[capacity].Count; i++)
{
Console.Write($"{items[capacity][i]} ");
}
}
}
}
注:这里使用动态规划求解背包问题,dp数组表示背包容量为j时,最多能装多少个物品。items列表记录每个容量下装的物品编号列表。
示例:
public class Item
{
public int Weight { get; set; }
}
public class Bag
{
public int Capacity { get; set; }
public List<Item> Items { get; set; }
public int UsedCapacity { get; set; }
}
public class GreedyAlgorithm
{
public List<Bag> Greedy(List<Item> items, int capacity)
{
// 根据重量将物品从大到小排序
items.Sort((item1, item2) => item2.Weight - item1.Weight);
// 初始化背包列表
List<Bag> bags = new List<Bag>();
// 遍历物品
for (int i = 0; i < items.Count; i++)
{
Item item = items[i];
// 如果当前物品的重量大于背包的容量,则新建一个背包
if (item.Weight > capacity)
{
bags.Add(new Bag
{
Capacity = capacity,
UsedCapacity = 0,
Items = new List<Item> { item }
});
}
// 否则尝试将物品放入已有的背包中
else
{
// 遍历已有的背包,尝试将物品放入
foreach (Bag bag in bags)
{
// 如果背包的剩余容量足够放入当前物品,则放入背包
if (bag.Capacity - bag.UsedCapacity >= item.Weight)
{
bag.Items.Add(item);
bag.UsedCapacity += item.Weight;
break;
}
}
}
}
return bags;
}
}
using System;
namespace KnapsackProblem
{
class Program
{
static void Main(string[] args)
{
int[] weights = {2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; // 物品重量
int n = weights.Length; // 物品数量
int capacity = 30; // 背包容量
int[,] dp = new int[n + 1, capacity + 1]; // 状态数组
// 初始化状态数组
for (int j = 0; j <= capacity; j++)
{
dp[0, j] = int.MaxValue; // 背包容量为 j 时,前 0 个物品最少需要的背包数为 int.MaxValue
}
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= capacity; j++)
{
dp[i, j] = dp[i - 1, j]; // 不选第 i 个物品
if (j >= weights[i - 1] && dp[i - 1, j - weights[i - 1]] != int.MaxValue)
{
dp[i, j] = Math.Min(dp[i, j], dp[i - 1, j - weights[i - 1]] + 1); // 选第 i 个物品
}
}
}
// 最少需要的背包数
int minBags = dp[n, capacity];
Console.WriteLine("最少需要的背包数:" + minBags);
// 求解背包装的物品
int[] bags = new int[minBags];
int k = capacity;
for (int i = n; i > 0 && k > 0; i--)
{
if (dp[i, k] == dp[i - 1, k]) // 第 i 个物品未选
{
continue;
}
bags[--minBags] = i - 1; // 第 minBags 个背包装的物品是 i-1
k -= weights[i - 1]; // 背包剩余容量
}
// 输出每个背包装的物品
for (int i = 0; i < bags.Length; i++)
{
Console.Write("第 " + (i + 1) + " 个背包装的物品:");
for (int j = 0; j < n; j++)
{
if (bags[i] == j)
{
Console.Write(j + " ");
}
}
Console.WriteLine();
}
}
}
}