Ответ 1
Этот &
является bitwise-AND
Оператор bitwise-AND сравнивает каждый бит своего первого операнда с соответствующий бит его второго операнда. Если оба бита равны 1, соответствующий бит результата устанавливается равным 1. В противном случае соответствующий бит результата равен 0.
Пока этот >>
является оператором с правым сдвигом
Оператор правого сдвига ( → ) сдвигает свой первый операнд справа на количество бит, заданных его вторым операндом.
Сказав это, возьмем следующее выражение
if (((i >> j) & 1) != 1) continue;
и попытайтесь понять это.
Изначально этот i >> j
будет смещать правые биты i
на позиции j
.
Например, допустим следующее назначение:
int number = 5;
Двоичное представление number
:
0000 0000 0000 0000 0000 0000 0000 0101
Если мы определяем новое целое число как:
int shiftNumbersBitByOne = a >> 1;
Тогда двоичное представление shiftNumbersBitByOne
будет:
0000 0000 0000 0000 0000 0000 0000 0010
Затем по результату этой операции и 1 мы применяем побитовый оператор И.
Что именно этот оператор?
Несмотря на то, что определение ясно, пример сделает его более понятным.
Пусть у нас есть двоичные числа a
и b
, то результатом a&b
является следующее:
a = 0001 0100 1010 0001 1000 1010 1101 0011
b = 0010 1100 1111 0111 0011 1010 1011 0111
a & b = 0000 0100 1010 0001 0000 1010 1001 0011
При этом в этой операции (i >> j) & 1
мы применяем побитовый-И-оператор между результатом i >> j
и двоичным представлением 1
0000 0000 0000 0000 0000 0000 0000 0001
Когда результатом
(i >> j) & 1
будет 1?
Это произойдет тогда и только тогда, когда последняя цифра i >> j
равна 1.
Обновление
Выше мы обратились к части как - я понятия не имею, как они работают. Теперь мы рассмотрим часть почему - почему они находятся в коде.
Давайте определим нашу проблему, проблему Рюкпак. Согласно wikipedia
Проблема с рюкзаком или проблема с рюкзаком - проблема в комбинаторной Оптимизация: учитывая набор элементов, каждый из которых имеет массу и значение, определить количество каждого элемента для включения в коллекцию, чтобы общий вес меньше или равен заданному пределу, а общий значение как можно больше.
В соответствии с вышесказанным, просто, что
// This is the total weight limit.
public double Capacity { get; set; }
и
// This is an array with all the given items.
public Item[] Items { get; set; }
Кроме того, на основе вашего кода мы можем сделать вывод, что каждый элемент имеет значение и вес, к которым можно получить доступ как item.v
и item.w
соответственно. Я предлагаю вам переименовать его в значение и вес соответственно, чтобы ваш код был более значимым.
По-видимому, это int size = Items.Length;
- количество доступных элементов.
Весь смысл того, почему часть начинается здесь:
var permutations = (long)Math.Pow(2,size);
Что такое permutations
? Что означает permutations
?
Прежде чем ответить на этот вопрос, подумайте о том, как мы можем представить, какие элементы коллекции предметов будут использоваться в конечном решении. Я утверждаю, что мы можем представить это с n-битным числом при условии, что у нас есть n элементов. Как это возможно? Если каждый бит в n-битовом номере относится к одному из n-элементов, довольно очевидно, что мы можем это сделать. Значение n-го бита будет 0, если n-й элемент не будет включен в окончательное решение. Хотя это значение будет равно 1, если оно будет включено.
Говоря довольно ясно, что представляют собой перестановки. Он представляет все возможные комбинации элементов в конечном решении. Это понятно, потому что каждый бит может иметь 2 значения, либо 0, либо 1. Учитывая, что у нас есть n-биты, число возможных комбинаций равно 2 ^ n.
Собственно, по этой причине этот алгоритм является алгоритмом грубой силы (мы делаем исчерпывающий поиск). Мы находим все возможные комбинации, чтобы найти лучший. В следующем цикле:
for (int i = 0; i<permutations; i++)
{
// ...
}
вы выполняете все возможные комбинации.
Затем для каждой комбинации вы просматриваете коллекцию предметов:
for (int j = 0; j < size; j++)
{
// Here you check if the item in position j
// is included in the current combination.
// If it is not, you go to the next value of the loop variable
// and you make the same check.
if(((i>>j)&1)!=1)
continue;
// The j-th item is included in the current combination.
// Hence we add it's
// value to the total value accumulator and it weight to
// the total weight accumulator.
total += Items[j].v;
weight += Items[j].w;
}
Теперь, если значение weight
меньше предельного значения и, общее значение больше, чем лучшее текущее общее значение, мы выбираем эту комбинацию как лучшую в настоящий момент:
bestPosition = i;
bestValue = total;
В конце концов, пройдя все доступные комбинации, у нас будет лучший.
Найдя наилучшую комбинацию, мы должны просмотреть элементы, чтобы увидеть, какие из них включены в эту комбинацию.
// The include is a list that will hold the items of the best combination.
var include = new List<Item>();
// We loop through all the available items
for (int j = 0; j<size; j++)
{
// If the items is included in the best combination,
// add this item to the include list.
if (((bestPosition>>j) & 1)==1)
include.Add(Items[j]);
}