E017. Перебор всех подмасок данной маски
Источник: e-maxx.ru/algo, страница PDF 47.
Перебор подмасок фиксированной маски
Дана битовая маска
. it is required эффективно перебрать все её подмаски, т.е. такие маски
, в которых могут
быть включены только те биты, которые были включены в маске
. Сразу рассмотрим реализацию этого 算法а, основанную на трюках с битовыми операциями:
int s = m;
while (s > 0) {
... можно использовать s ...
s = (s-1) & m;
}
или, используя более компактный оператор
:
for (int s=m; s; s=(s-1)&m)
... можно использовать s ... Единственное исключение для обоих вариантов кода — подмаска, равная нулю, обработана не будет. Её обработку придётся выносить из цикла, или использовать менее изящную конструкцию, на示例:
for (int s=m; ; s=(s-1)&m) {
... можно использовать s ...
if (s==0) break;
} Разберём, почему приведённый выше код действительно находит все подмаски данной маски, причём без повторений, за O (их количества), и в порядке убывания.
Пусть у нас есть текущая подмаска
, и мы хотим перейти к следующей подмаске. Отнимем от маски
единицу, тем
самым мы снимем самый правый единичный бит, а все биты правее него поставятся в
. Затем удалим все
"лишние" единичные биты, которые не 输入ят в маску
и потому не могут 输入ить в подмаску. Удаление
осуществляется битовой операцией
. В результате мы "обрежем" маску
до того наибольшего
значения, которое она может принять, т.е. до следующей подмаски после в порядке убывания. Таким образом, этот 算法 генерирует все подмаски данной маски в порядке строгого убывания, затрачивая на каждый переход по две elementарные операции.
Особо рассмотрим момент, когда
. После выполнения
мы получим маску, в которой все биты
включены (битовое представление числа
), и после удаления лишних битов операцией
получится
не что иное, как маска
. Поэтому с маской
следует быть осторожным — если вовремя не остановиться
на нулевой маске, то 算法 может войти в бесконечный цикл.
Перебор всех масок с их подмасками. Оценка
Во многих 题目х, особенно на dynamic programming по маскам, it is required перебирать все маски, и для каждой маски - все подмаски:
for (int m=0; m<(1<<n); ++m)
for (int s=m; s; s=(s-1)&m)
... использование s и m ...
Докажем, что внутренний цикл суммарно выполнит
итераций.
证明: 1 способ. Рассмотрим
-ый бит. Для него, вообще говоря, есть ровно три варианта: он
не 输入ит в маску
(и потому в подмаску
); он 输入ит в
, но не 输入ит в
; он 输入ит в
и в
. Всего битов
, поэтому всего различных комбинаций будет
, что и требовалось доказать.
证明: 2 способ. Заметим, что если маска
имеет
включённых битов, то она будет иметь
подмасок. Поскольку масок длины
с
включёнными битами есть
(см. "биномиальные коэффициенты"), то
всего комбинаций будет: Посчитаем эту сумму. Для этого заметим, что она есть не что иное, как разложение в бином Ньютона
выражения
, т.е. , что и требовалось доказать.
C# 解法
自动草稿,提交前请检查using System;
using System.Collections.Generic;
using System.Linq;
public static class AlgorithmDraft
{
// Auto-generated C# draft from the original e-maxx C/C++ listing. Review before production use.
int s = m;
while (s > 0) {
... можно использовать s ...
s = (s-1) & m;
}
for (int s=m; s; s=(s-1)&m)
... можно использовать s ...
for (int s=m; ; s=(s-1)&m) {
... можно использовать s ...
if (s==0) break;
}
for (int m=0; m<(1<<n); ++m)
for (int s=m; s; s=(s-1)&m)
... использование s и m ...
}
C++ 解法
匹配/原始int s = m;
while (s > 0) {
... можно использовать s ...
s = (s-1) & m;
}
for (int s=m; s; s=(s-1)&m)
... можно использовать s ...
for (int s=m; ; s=(s-1)&m) {
... можно использовать s ...
if (s==0) break;
}
for (int m=0; m<(1<<n); ++m)
for (int s=m; s; s=(s-1)&m)
... использование s и m ...
Java 解法
自动草稿,提交前请检查import java.util.*;
import java.math.*;
public class AlgorithmDraft {
// Auto-generated Java draft from the original e-maxx C/C++ listing. Review before production use.
int s = m;
while (s > 0) {
... можно использовать s ...
s = (s-1) & m;
}
for (int s=m; s; s=(s-1)&m)
... можно использовать s ...
for (int s=m; ; s=(s-1)&m) {
... можно использовать s ...
if (s==0) break;
}
for (int m=0; m<(1<<n); ++m)
for (int s=m; s; s=(s-1)&m)
... использование s и m ...
}
Материал разбит как 算法ическая 题目: изучить постановку, понять асимптотику и реализовать 算法 на выбранном языке.
Vacancies for this task
活跃职位 with overlapping task tags are 已显示.