using
System;
using
System.Collections.Generic;
class
Item
{
public
float
Weight {
get
; }
public
int
Value {
get
; }
public
Item(
float
weight,
int
value)
{
Weight = weight;
Value = value;
}
}
class
Node
{
public
int
Level {
get
; }
public
int
Profit {
get
;
set
; }
public
float
Weight {
get
;
set
; }
public
int
Bound {
get
;
set
; }
public
Node(
int
level,
int
profit,
float
weight)
{
Level = level;
Profit = profit;
Weight = weight;
}
}
class
KnapsackBranchAndBound
{
static
Comparison<Item> itemComparison = (a, b) =>
{
double
ratio1 = (
double
)a.Value / a.Weight;
double
ratio2 = (
double
)b.Value / b.Weight;
return
ratio2.CompareTo(ratio1);
};
static
int
Bound(Node u,
int
n,
int
W, Item[] arr)
{
if
(u.Weight >= W)
return
0;
int
profitBound = u.Profit;
int
j = u.Level + 1;
float
totalWeight = u.Weight;
while
(j < n && totalWeight + arr[j].Weight <= W)
{
totalWeight += arr[j].Weight;
profitBound += arr[j].Value;
j++;
}
if
(j < n)
profitBound += (
int
)((W - totalWeight) * arr[j].Value / arr[j].Weight);
return
profitBound;
}
static
int
Knapsack(
int
W, Item[] arr,
int
n)
{
Array.Sort(arr, itemComparison);
PriorityQueue<Node> priorityQueue =
new
PriorityQueue<Node>((a, b) => b.Bound.CompareTo(a.Bound));
Node u, v;
u =
new
Node(-1, 0, 0);
priorityQueue.Enqueue(u);
int
maxProfit = 0;
while
(priorityQueue.Count > 0)
{
u = priorityQueue.Dequeue();
if
(u.Level == -1)
v =
new
Node(0, 0, 0);
else
if
(u.Level == n - 1)
continue
;
else
v =
new
Node(u.Level + 1, u.Profit, u.Weight);
v.Weight += arr[v.Level].Weight;
v.Profit += arr[v.Level].Value;
if
(v.Weight <= W && v.Profit > maxProfit)
maxProfit = v.Profit;
v.Bound = Bound(v, n, W, arr);
if
(v.Bound > maxProfit)
priorityQueue.Enqueue(v);
v =
new
Node(u.Level + 1, u.Profit, u.Weight);
v.Bound = Bound(v, n, W, arr);
if
(v.Bound > maxProfit)
priorityQueue.Enqueue(v);
}
return
maxProfit;
}
static
void
Main()
{
int
W = 10;
Item[] arr = {
new
Item(2, 40),
new
Item(3.14f, 50),
new
Item(1.98f, 100),
new
Item(5, 95),
new
Item(3, 30)
};
int
n = arr.Length;
int
maxProfit = Knapsack(W, arr, n);
Console.WriteLine(
"Maximum possible profit = "
+ maxProfit);
}
}
class
PriorityQueue<T>
{
private
List<T> data;
private
Comparison<T> comparison;
public
PriorityQueue(Comparison<T> comparison)
{
this
.data =
new
List<T>();
this
.comparison = comparison;
}
public
void
Enqueue(T item)
{
data.Add(item);
int
childIndex = data.Count - 1;
while
(childIndex > 0)
{
int
parentIndex = (childIndex - 1) / 2;
if
(comparison(data[childIndex], data[parentIndex]) > 0)
{
T tmp = data[childIndex];
data[childIndex] = data[parentIndex];
data[parentIndex] = tmp;
}
else
{
break
;
}
childIndex = parentIndex;
}
}
public
T Dequeue()
{
int
lastIndex = data.Count - 1;
T frontItem = data[0];
data[0] = data[lastIndex];
data.RemoveAt(lastIndex);
lastIndex--;
int
parentIndex = 0;
while
(
true
)
{
int
childIndex = parentIndex * 2 + 1;
if
(childIndex > lastIndex)
break
;
int
rightChild = childIndex + 1;
if
(rightChild <= lastIndex && comparison(data[rightChild], data[childIndex]) > 0)
childIndex = rightChild;
if
(comparison(data[parentIndex], data[childIndex]) > 0)
break
;
T tmp = data[parentIndex];
data[parentIndex] = data[childIndex];
data[childIndex] = tmp;
parentIndex = childIndex;
}
return
frontItem;
}
public
int
Count
{
get
{
return
data.Count; }
}
}