Многие задачи заключаются в нахождении одного или нескольких искомых из полного набора некоторых вариантов. Эти задачи называются задачами выбора на наборе дискретных данных. Самый простой способ решения задачи выбора - перебрать все варианты и выбрать среди них те, которые требуются по условию.  
Плюсом данного метода является гарантированное получение точного и полного результата. Главным минусом - большая временная сложность алгоритма при большом наборе исходных данных
## Реализация
#### 1. Перебор циклами
Программа представляет собой несколько вложенных циклов, которые и перебираются все варианты  
**Пример:** найти количество счастливых автобусных билетов
```cpp
#include <iostream>
using namespace std;

int main() {
	int col = 0;
	for (int a = 0; a <= 9; a++)
		for (int b = 0; b <= 9; b++)
			for (int c = 0; c <= 9; c++)
				for (int d = 0; d <= 9; d++)
					for (int e = 0; e <= 9; e++)
						for (int f = 0; f <= 9; f++)
							if (a + b + c == d + e + f) col++;
	cout << col << " " << col / 10000.0 << endl;
	system("pause");
	return 0;
}
```
Преимущества перебора циклами - простота реализации.  
Недостатки - часто заранее неизвестно, какое количество циклов нужно вкладывать друг в друга
#### 2. P-ичный перебор
Имеется $n$ объектов, каждому из которых поставлена в соответствие некоторая стоимость. Разделить объекты на 2 группы так, чтобы разность стоимости между группами была минимальной.  
Поскольку каждый объект может оказаться в одной из 2 куч, закрепим за каждым из объектов двоичное число - 0 или 1. Если количество объектов $N$ большое, для полного перебора необходимо просмотреть все комбинации $N$-значных двоичных чисел от $N$ нулей до $N$ единиц. Всего вариантов - $2^N$. Для реализации помимо массива объектов можно завести массив нулей и единиц, считая его двоичным числом, на каждом шаге при выборе нового варианта прибавляя к этому числу 1.  
Данная задача решена методом полного двоичного перебора:
```cpp
#include <iostream>

void plus(int* m, int n) {
	int i = n;
	while (m[i] == 1)
		m[i--] = 0;
	m[i] = 1;
}

int main() {
	const int n = 5;
	int min = 15;
	int m[n + 1] = { 0,1,2,3,4,5 }, bin[n + 1] = { 0,0,0,0,0,0 }, itog[n + 1] = { 0,0,0,0,0,0 };
	while (bin[0] == 0) {
		int s1 = 0, s2 = 0;
		for (int i = 1; i <= n; i++)
			if (bin[i] == 0) s1 += m[i];
			else s2 += m[i];
		if (abs(s1 - s2) < min) {
			min = abs(s1 - s2);
			for (int j = 1; j <= n; j++)
				if (itog[j] == 0) {
					std::cout << m[j] << " "; {
						std::cout << std::endl;
						std::cout << "2 group: "; 
					}
				}
			for (int j = 1; j <= n; j++) {
				if (itog[j] == 1) std::cout << m[j] << " "; {
					std::cout << std::endl;
					std::cout << "2 group: "; 
				}
			}
		}
		plus(bin, n);
	}
	std::cout << min << std::endl;
}

```

В общем случае перебор может быть P-ичным.  
Пример: числа 1 2 3 4 5 6 7 8 записаны один за другим. Расставить между ними знаки $+$, $-$, $*$,  $/$ или ничего так, чтобы в итоге получилось заданное число $N$. Задачу можно решить полным пятеричным перебором. Количество вариантов - $5^8$.
#### 3. Рекурсивный перебор
Дан квадратный числовой массив. Найти такой путь из левого верхнего угла массива в правый нижний, чтобы сумма чисел по данному пути была максимальной. Из каждого элемента массива допустимо двигаться только вправо или вниз

| 2 | 1 | 1 | 1 |
| ---- | ---- | ---- | ---- |
| 1 | 2 | 1 | 1 |
| 1 | 1 | 2 | 1 |
| 1 | 1 | 1 | 2 |
```cpp
#include <iostream>
using namespace std;

int Max = 0;
void poisk(int** m, int n, int i, int j, int s) {
	s += m[i][j];
	if (i == n - 1 && j == n - 1 && s > Max) Max = s;
	if (i < n - 1) poisk(m, n, i + 1, j, s);
	if (j < n - 1) poisk(m, n, i, j + 1, s);
}

int main() {
	const int n = 10;
	int m[n][n] = { {1,1,1,1,1}, 
					{1,1,1,1,1}, 
					{1,2,1,1,1}, 
					{1,1,1,2,1}, 
					{1,1,1,1,1} };
	int** a = new int* [n];
	for (int i = 0; i < n; i++) {
		a[i] = new int[n];
		for (int j = 0; j < n; j++) {
			a[i][j] = 1; //m[i][j];
		}
	}
	poisk(a, n, 0, 0, 0);
	cout << Max << endl;
	system("pause");
	return 0;
}
```

Основной плюс функции рекурсивного перебора в ее простоте и компактности. Минусы рекурсивного перебора - возможное переполнение стека и медленная работа.