Вчера я написал вопрос об этой же задаче, слегка улучшил свой алгоритм, но всё таки хотел бы узнать как можно решить её алгоритмом перебора.
Юного программиста Васю заинтересовал следующий вопрос: предположим,
что мы взвешиваем боксёров на чашечных весах и пользуемся двумя
двоичными наборами гирь: граммовым и килограммовым. Понятно, что
граммовый набор является стандартным и состоит из гирек весом в 1, 2,
4, 8, 16, 32, 64, 128, 256, 512 и 1024 грамм. Аналогично обстоит дело
и с килограммовым набором – просто гири потяжелее, но при этом их
немного меньше… Для простоты далее в этой задаче будем считать, что
волшебным образом на прошедшей олимпиаде оказалось, что вес каждого
спортсмена в точности мог быть измерен только килограммовым набором.
Найти количество гирь.
40 <= вес спортсмена <= 130.
Суть в том, что я даже не понимаю что да как с этим алгоритмом. Что он должен перебирать? Рассмотрим пример моего решения.
У меня есть число n = 97
(для примера).
Его соседи из массива w[]
есть 128 < 97 < 64
.
Сперва проверим разницу между первым: 128 - 97 = 31
, а потом и вторым: 97 - 64 = 33
.
Видем, что 31 < 33
, по-этому n = w[i] (тоесть 128) - n
. А в другом случаи n -= w[i + 1] (тоесть 64, а не 128)
.
Делаем так до тех пор, пока n > 0
.
Но, могу ли я считать это алгоритмом перебора? Я же здесь толком то и ничего не перебираю. Возможно Вы знаете какой-то другой вариант решения нужным мне способом!?
#include <iostream>
using namespace std;
int w[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 };
int neighbor(int n)
{
int i = 0;
while (n > 0)
{
if (n - w[i] < 0)
{
i++;
}
if (n - w[i] >= 0)
{
return i;
break;
}
}
}
int main()
{
int n;
cin >> n;
int i, count = 0;
while (n > 0)
{
i = neighbor(n) - 1;
if (w[i] - n < n - w[i + 1])
{
count++;
n = w[i] - n;
}
else if (w[i] - n >= n - w[i + 1])
{
n -= w[i + 1];
count++;
}
}
cout << count << endl;
system("pause");
return 0;
}
Учитывая, что вес гирь это степени двойки, его можно рассматривать как набор бит в числе. Тогда нам будет проще работать в ними, как с обычными двоичными числами. Наша задача найти такой набор бит, который надо добавить к весу спортсмена и набор бит, которые положить на другую чашу. При этом нам надо что бы не было одинаковых бит среди добавленных на левую чашу и положенных на правую. Из всех вариантов нам надо выбрать тот, в котором будет минимальное количество бит в сумме из добавленных на левую и положенных на правую.
Просто пробуем перебрать все возможные наборы гирь, добавляемых на левую чашу. Если взять крайние случаи и вес спортсмена выходящий за рамки задачи нам надо будет проверить максимум 2047 вариантов.
int main() {
int c,s,bits;
int n=508; // Вес спортсмена, находящегося на левой чаше весов
int min=0xFFFF, min_c=0;
for(c=0;c<=2047;c++) {
s=n+c; // Добавляем набор гирь на левую чашу, получаем уравновешивающий
// вес, необходимый на правой чаши
if((s & c) != 0) // Если в добавленном наборе гирь на леву чашу
continue; // и необходимом наборе на правой чаше есть одинаковые
// гири - то не рассматриваем этот вариант
s=s | c; // Получаем сумму гирь на левой и правой чаше
bits=0;
for (; s; bits++) s &= (s - 1); // И считаем их количество
if(min > bits) { // Если нашли количество меньшее, чем ранее, запоминаем
min=bits;
min_c=c;
}
}
printf("min=%d for left %d right %d\n",min,min_c,min_c+n);
}
Мое решение имеет идею перебора , давайте представим , что каждому предмету мы можем сопоставить число 1 , если мы его берем на левые весы(то есть они прибавляют вес спортсмену) , число 0 , если они не используются и -1 если они противовес спортсмену.Тогда мы сможем перебрать все значение за 3^(k) , где k - количество предметов для задачи это 531441 операций , что нас устраивает.Код задачи приведен ниже.Засчитаное решение на e-olymp
#include <iostream>
using namespace std;
int x , p = 8;
int arr[12] = {0 , 1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 , 256 , 512 , 1024} , k = 0;//индексация массива с елиницы
void du(int c , int r[12])
{
if(c == 11)//когда мы набрали нужное количество гирь
{
k++;
int sum = 0 , l = 0;
for(int i = 1;i < 12;i++)//проходим по предметам
{
sum += arr[i] * r[i];//в зависимости от места прибавляем , отнимаем или ничего не делаем
if(r[i])
l++;
}
if(sum == x)
{
p = min(l , p);//нам нужно минимальное количество
}
return ;
}
//вызов всех возможных вариантов
r[c+1] = 0;
du(c+1 , r);
r[c+1] = 1;
du(c+1 , r);
r[c+1] = -1;
du(c+1 , r);
}
int main()
{
cin >> x;
int arr[12] = {0};//текущий набор(0 , 1 ,-1)согласно описанию више
du(0 , arr);
cout << p;//вывод ответа
}
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Есть приложение, надо создать ImageView, чтобы она отображалась пока работает программа
Пишу crud приложение по примерам из открытых источниковПри открытии моего единственного jsp файла
Я хочу использовать MVP и картуДля первого запуска работает все идеально, но когда я вращаю телефон получаю NullExeption в addMarkersOnMap потому что GoogleMap...
Извиняюсь за глупый вопрос но уже довольно долго сижу над элементарной вещьюДля работы с VK API решил использовать их SDK