1-0 (one item of each type)
Bounded (several items of the same type)
Unbounded (unlimited number of items of the same type)
How can we describe the dynamic programming algorithm for solving type 2?"
1-0 (one item of each type)
Bounded (several items of the same type)
Unbounded (unlimited number of items of the same type)
使用0-1变种,但允许在解决方案中重复一个项目,重复次数取决于其边界指定的次数。您需要维护一个向量,记录已包含在部分解决方案中的每个项目的副本数量。
O(物品数量 * 最大重量 * 总物品数)
。O(物品数量 * 最大重量 * sqrt(最大重量))
。
O(number of items * maximum weight * log(maximum weight))
:https://codeforces.com/blog/entry/65202?#comment-492168
另一种思考上述方法的方式如下:w
,当前物品的重量/成本
- v
,当前物品的价值
- n
,可用于使用的当前物品副本数2^k - 1
个当前类型项目的方式相同。这是因为我们可以通过取与二进制表示n'
对应的上述项目的组合来模拟任意数量的项目(对于所有整数k'
,如果表示2^k'
的位被设置,则取代表2^k'
个当前类型项目的项目)。
n - (2^k - 1)
的集合位对应的项目。(对于所有整数k'
,如果表示2^k'
的位被设置,则插入(2^k' * w, 2^k' * v)
)。n
个当前类型项目的获取。
目前我没有确切的证明这个解法的方法,但是在尝试了一段时间之后,它似乎是正确的。如果我找到证明,我可能会稍后更新这篇文章。
首先,提出一个命题:我们只需要证明插入上述项目可以让我们模拟取走当前类型的任意数量物品,最多不超过n
个。
有了这个想法,让我们定义一些变量:
n
为当前类型可用物品的数量x
为我们希望取走的当前类型物品的数量k
是最大的整数,使得2^k <= n
如果x < 2^k
,我们可以轻松地使用算法第一阶段描述的方法取走x
件物品:
>= 2^k
,那么x - (n + 1) >= 0
为真,意味着x > n
。 这是不可能的,因为那不是x
的有效值。
最后,这里提到了一种方法在这里,它的运行时间为O(物品数量 * 最大重量)
。
该算法类似于ic3b3rg提出的暴力方法,只是使用了简单的DP优化和滑动窗口deque来降低运行时间。
我的代码已经在这个问题上进行了测试(经典有界背包问题):https://dmoj.ca/problem/knapsack
我在Code Project上发布了一篇文章,讨论了更有效的有界背包算法解决方案。
从文章中可以看出:
在动态规划解决方案中,m数组的每个位置都是容量为j的子问题。在0/1算法中,对于每个子问题,我们考虑将每个物品的一个副本添加到背包中的价值。在下面的算法中,对于每个子问题,我们考虑添加适合数量或每个物品的可用数量中较小的那个数量的价值。
我还改进了代码,以便我们可以确定优化后的背包中有哪些物品(而不仅仅是优化后的价值)。
ItemCollection[] ic = new ItemCollection[capacity + 1];
for(int i=0;i<=capacity;i++) ic[i] = new ItemCollection();
for(int i=0;i<items.Count;i++)
for(int j=capacity;j>=0;j--)
if(j >= items[i].Weight) {
int quantity = Math.Min(items[i].Quantity, j / items[i].Weight);
for(int k=1;k<=quantity;k++) {
ItemCollection lighterCollection = ic[j - k * items[i].Weight];
int testValue = lighterCollection.TotalValue + k * items[i].Value;
if(testValue > ic[j].TotalValue) (ic[j] = lighterCollection.Copy()).AddItem(items[i],k);
}
}
private class Item {
public string Description;
public int Weight;
public int Value;
public int Quantity;
public Item(string description, int weight, int value, int quantity) {
Description = description;
Weight = weight;
Value = value;
Quantity = quantity;
}
}
private class ItemCollection {
public Dictionary<string,int> Contents = new Dictionary<string,int>();
public int TotalValue;
public int TotalWeight;
public void AddItem(Item item,int quantity) {
if(Contents.ContainsKey(item.Description)) Contents[item.Description] += quantity;
else Contents[item.Description] = quantity;
TotalValue += quantity * item.Value;
TotalWeight += quantity * item.Weight;
}
public ItemCollection Copy() {
var ic = new ItemCollection();
ic.Contents = new Dictionary<string,int>(this.Contents);
ic.TotalValue = this.TotalValue;
ic.TotalWeight = this.TotalWeight;
return ic;
}
}
例如,尝试使用{2(2次),4(3次),...}的有界背包等效于使用{2,2,4,4,4,...}解决1-0背包问题。
我建议您使用背包分数贪心算法。它的复杂度是O(n log n),是最好的算法之一。 下面我在c#中提供了它的代码。
private static void Knapsack()
{
Console.WriteLine("************Kanpsack***************");
Console.WriteLine("Enter no of items");
int _noOfItems = Convert.ToInt32(Console.ReadLine());
int[] itemArray = new int[_noOfItems];
int[] weightArray = new int[_noOfItems];
int[] priceArray = new int[_noOfItems];
int[] fractionArray=new int[_noOfItems];
for(int i=0;i<_noOfItems;i++)
{
Console.WriteLine("[Item"+" "+(i+1)+"]");
Console.WriteLine("");
Console.WriteLine("Enter the Weight");
weightArray[i] = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Enter the Price");
priceArray[i] = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("");
itemArray[i] = i+1 ;
}//for loop
int temp;
Console.WriteLine(" ");
Console.WriteLine("ITEM" + " " + "WEIGHT" + " "+"PRICE");
Console.WriteLine(" ");
for(int i=0;i<_noOfItems;i++)
{
Console.WriteLine("Item"+" "+(i+1)+" "+weightArray[i]+" "+priceArray[i]);
Console.WriteLine(" ");
}//For Loop For Printing the value.......
//Caluclating Fraction for the Item............
for(int i=0;i<_noOfItems;i++)
{
fractionArray[i] = (priceArray[i] / weightArray[i]);
}
Console.WriteLine("Testing.............");
//sorting the Item on the basis of fraction value..........
//Bubble Sort To Sort the Process Priority
for (int i = 0; i < _noOfItems; i++)
{
for (int j = i + 1; j < _noOfItems; j++)
{
if (fractionArray[j] > fractionArray[i])
{
//item Array
temp = itemArray[j];
itemArray[j] = itemArray[i];
itemArray[i] = temp;
//Weight Array
temp = weightArray[j];
weightArray[j] = weightArray[i];
weightArray[i] = temp;
//Price Array
temp = priceArray[j];
priceArray[j] = priceArray[i];
priceArray[i] = temp;
//Fraction Array
temp = fractionArray[j];
fractionArray[j] = fractionArray[i];
fractionArray[i] = temp;
}//if
}//Inner for
}//outer For
// Printing its value..............After Sorting..............
Console.WriteLine(" ");
Console.WriteLine("ITEM" + " " + "WEIGHT" + " " + "PRICE" + " "+"Fraction");
Console.WriteLine(" ");
for (int i = 0; i < _noOfItems; i++)
{
Console.WriteLine("Item" + " " + (itemArray[i]) + " " + weightArray[i] + " " + priceArray[i] + " "+fractionArray[i]);
Console.WriteLine(" ");
}//For Loop For Printing the value.......
Console.WriteLine("");
Console.WriteLine("Enter the Capacity of Knapsack");
int _capacityKnapsack = Convert.ToInt32(Console.ReadLine());
// Creating the valuse for Solution
int k=0;
int fractionvalue = 0;
int[] _takingItemArray=new int[100];
int sum = 0,_totalPrice=0;
int l = 0;
int _capacity = _capacityKnapsack;
do
{
if(k>=_noOfItems)
{
k = 0;
}
if (_capacityKnapsack >= weightArray[k])
{
_takingItemArray[l] = weightArray[k];
_capacityKnapsack = _capacityKnapsack - weightArray[k];
_totalPrice += priceArray[k];
k++;
l++;
}
else
{
fractionvalue = fractionArray[k];
_takingItemArray[l] = _capacityKnapsack;
_totalPrice += _capacityKnapsack * fractionArray[k];
k++;
l++;
}
sum += _takingItemArray[l-1];
} while (sum != _capacity);
Console.WriteLine("");
Console.WriteLine("Value in Kg Are............");
Console.WriteLine("");
for (int i = 0; i < _takingItemArray.Length; i++)
{
if(_takingItemArray[i]!=0)
{
Console.WriteLine(_takingItemArray[i]);
Console.WriteLine("");
}
else
{
break;
}
enter code here
}//for loop
Console.WriteLine("Toatl Value is "+_totalPrice);
}//Method