Я пытаюсь вычислить сумму всех возможных комбинационных чисел в векторе. Если комбинация равна заданному числу, функция возвращает false. Если никакая комбинация не равна этому числу, массив печатает число и возвращает true.
Это то, что у меня есть:
bool t(vector<int>vi, int num){
for(int i = 0; i < vi.size(); i++) {
int sum=vi[i];
for(int j = i+1; j < d.size(); j++) {
if(sum + vi[j] == num) return false;
}
}
cout<< num << endl;
return true;
}
Как вы можете видеть, я могу рассчитать один уровень сумм чисел с учетом корневой точки, но я застрял там, где мне нужно продолжить ветвление выше. Кажется, что если бы этот метод вызывал сам себя и рекурсивно продвигался по веткам, но я не могу понять, как это сделать.
Рекурсия - отличный способ решить эту проблему.
bool t_helper(vector<int>::const_iterator it, vector<int>::const_iterator end, int sum_left)
{
if (sum_left == 0) return false;
if (it == end) return true;
return t_helper(it+1, end, sum_left - *it) && t_helper(it+1, end, sum_left);
}
bool t(const vector<int>& vi, int num)
{
bool result = t_helper(vi.begin(), vi.end(), num);
if (result) cout << num << endl;
return result;
}
Если вы знаете что-то лишнее, вы можете рано выйти. Например, если элементы vi
неотрицательны, то если sum_left
становится отрицательным, вы можете пропустить остальную часть этой ветки. Такие методы "обрезки" часто делают такой подход быстрее, чем исчерпывающая итерация.
Еще одно предложение обрезки - вернуть другое значение, когда включение всех положительных элементов на ветке (и только положительные элементы) не соответствует цели. Это означает, что подмножество также не может достичь цели.
sum_left
в t()
даже не объявив его?
Математически вы можете сделать это итеративно, представив массив как двоичную строку длины n
. При каждом индексе он равен 1
или 0
. Если оно равно 1
, то мы добавляем его в сумму, а если оно равно 0
, мы исключаем его из суммы.
Все, что вам нужно сделать, - пройти через каждую возможную длину n
двоичной строки от 000....000
до 111....111
и суммировать в зависимости от того, какие индексы активированы.
Что касается прохождения всех возможных двоичных строк, вы можете иметь массив размером n
который начинается со всех индексов, установленных в 0
. Затем вы просто зацикливаете до тех пор, пока он не станет массивом со всеми индексами, установленными в 1
. На каждой итерации цикла вы добавляете 1
к биту с индексом n - 1
. Если этот бит равен 1
, установите его в 0
и переносите и добавьте 1
в бит в позиции n - 2
и т.д. (Делая двоичное добавление).
n < 32
, вы можете использовать непосредственно uint32_t
.