Если нам разрешено заполнять таблицу всеми нулями, чтобы начать, то должна быть возможность выполнить точно 2^n - 1
заполнение, чтобы установить желаемые 1 биты. Это не может быть быстрее, чем написание ручного цикла, хотя оно полностью непрофильно.
EDIT:
Линия std::vector<std::vector<int> > output(n, std::vector<int>(1 << n));
объявляет вектор векторов. Внешний вектор имеет длину n, а внутренний - 2^n
(число результатов истинности для n входов), но я делаю вычисление мощности, используя сдвиг влево, чтобы компилятор мог вставить константу вместо вызова, скажем, pow
. В случае, когда n=3
, мы получаем вектор 3х8. Я организовал это таким образом (вместо обычного 8x3 со строкой в качестве первого индекса), потому что мы собираемся использовать шаблон на основе столбцов в выходных данных. Таким образом, использование конструкторов vector
также гарантирует, что каждый элемент вектора векторов инициализируется равным 0. Таким образом, нам остается только беспокоиться о том, чтобы установить значения, которые мы хотим, равными 1, и оставить остальные в покое.
Второй набор вложенных циклов for
просто используется для распечатки результирующих данных, когда все готово, ничего особенного.
Первый набор циклов for реализует реальный алгоритм. Мы используем преимущества шаблона на основе столбцов в выходных данных здесь. Для данной таблицы истинности самый левый столбец будет состоять из двух частей: первая половина - все 0, а вторая половина - все 1. Так как мы предварительно заполнили нули, то будет применена одна заливка половины высоты столбца, начиная с половины. все 1, нам нужно. Во втором столбце будут строки 1/4-й 0, 1/4-й 1, 1/4-й 0, 1/4-й 1. Таким образом, два заполнения будут применять все 1, которые нам нужны. Мы повторяем это до тех пор, пока не доберемся до самого правого столбца, в этом случае каждая вторая строка будет 0 или 1.
Мы начинаем говорить: «Мне нужно заполнить половину строк одновременно» (unsigned num_to_fill = 1U << (n - 1);
). Затем мы зациклились на каждом столбце. Первый столбец начинается с позиции, которую нужно заполнить, и заполняет столько строк на 1. Затем мы увеличиваем строку и уменьшаем размер заливки наполовину (теперь мы заполняем 1/4 строки сразу, но затем пропускаем пустое место). строк и заполните второй раз) для следующего столбца.
Например:
#include <iostream>
#include <vector>
int main()
{
const unsigned n = 3;
std::vector<std::vector<int> > output(n, std::vector<int>(1 << n));
unsigned num_to_fill = 1U << (n - 1);
for(unsigned col = 0; col < n; ++col, num_to_fill >>= 1U)
{
for(unsigned row = num_to_fill; row < (1U << n); row += (num_to_fill * 2))
{
std::fill_n(&output[col][row], num_to_fill, 1);
}
}
// These loops just print out the results, nothing more.
for(unsigned x = 0; x < (1 << n); ++x)
{
for(unsigned y = 0; y < n; ++y)
{
std::cout << output[y][x] << " ";
}
std::cout << std::endl;
}
return 0;
}