У Петра есть N шаров, пронумерованных от 1 до N.
Нет двух шаров весят одинаково. Вы хотите найти самый тяжелый мяч, но не знаете, какой это, и Питер не хочет просто дать его вам. Поэтому он решил поиграть с вами в игру.
Вы можете задать Петру не более Q = 4 + N / 2 вопросов. В каждом вопросе вы должны указать Петру номера пяти разных шаров, а Питер скажет вам номера 3-го и 4-го самых тяжелых из этих шаров. Найди номер самого тяжелого мяча!
Взаимодействие:
Во-первых, вы должны прочитать строку, содержащую одно целое число T, обозначающее количество тестовых случаев.
Для каждого теста вы должны начать с чтения строки, содержащей одно целое число N.
Чтобы задать вопрос, вы должны напечатать строку, содержащую символ «?», Пробел и пять разделенных пробелом целых чисел i1, i2, i3, i4 и i5: номера пяти разных шаров (в любом порядке).
Затем вы должны прочитать строку, содержащую два разделенных пробелом целых числа: номера 3-го и 4-го самых тяжелых шаров.
Чтобы завершить решение тестового примера, выведите строку, содержащую символ «!», Пробел и целое число im: номер самого тяжелого шара (1≤im≤N).
Не забудьте очистить вывод после печати каждой строки!
Ограничения:
Пример:
You Grader
1
6
? 1 2 3 4 5
3 4
? 1 2 3 4 6
3 4
? 1 2 3 5 6
3 5
? 1 2 4 5 6
4 5
? 1 3 4 5 6
4 5
? 2 3 4 5 6
4 5
! 6
Объяснение:
Шарики отсортированы в порядке убывания веса.
Это перефразирование проблемы в конкурсе кодефов, перефразированное потому, что первоначальное изложение проблемы было не очень ясным.
Вот мой код (для n> 6):
Я знаю, что это не очень эффективно, я редактировал его, пытаясь найти ошибку
(C ++)
Вся проблема сводится к поиску величайшего элемента из шести, у вас есть 4 + 6/2 = 7
пытается для. Для более чем шести элементов, с каждой попыткой, вы сортируете два из них (что вы уже сделали), так что вот где формула 4 + N/2
происходит от…
Первые пять тестов (фактически, все, что нам нужно / можно сделать) будут:
(6) 12345 34 // one of 1235 must be heavier than 34
(5) 12346 34 // one of 1236 must be heavier than 34
(4) 12356 35 // ...
(3) 12456 45
(2) 13456 45
(1) 23456 45
Пока мы можем быть уверены, что 3, 4 и 5 не могут быть самыми тяжелыми, оставаясь 1, 2, 6
Теперь давайте внимательно рассмотрим:
Удаление 5 или 6 из набора результатов дважды в том же 3-м и 4-м.
Удаление 4 из установленных результатов приводит к тому, что 3-я и 4-я комбинации встречаются только один раз.
Удаление 1, 2 или 3 из набора результатов три раза в том же 3-м и 4-м.
Что нас сейчас интересует, так это два набора с одинаковыми 3-м и 4-м точками, встречающимися дважды:
1, 2, 3, 4, 5 и 1, 2, 3, 4, 6. Из них мы знаем, что 5 или 6 должны быть самыми большими; в сочетании с самым первым наблюдением (3, 4, 5 исключено) остается только 6.
На самом деле, мы даже знаем больше:
Тот, который не выбран (5) из набора двух вхождений (5, 6), является вторым наиболее тяжелым, единственный случай 3-го / 4-го (4) показывает третий самый тяжелый, а оставшийся (3) из первоначально исключенных (3 , 4, 5) является четвертым по весу.
Только 5-й и 6-й не могут быть различены …
Редактировать: Фильтрация прибавочной стоимости:
Вы могли бы немного упростить свой код:
int t;
std::cin >> t;
while(t--) // sparse you another variable...
{
int n = 12;
--n; // exclude highest value!
int ar[] = {1, 2, 3, 4, 5}; // just *always* maintain the values in the array...
// note: the array is one larger as you had initially!
for (int i = 6; i < n; i = i + 2) // prefer local scope for i!
// ^ can start at a later point of time, we'll be replacing AFTERWARDS
{
std::cout << '?';
for(auto a : ar) // loop might or not be more elegant
std::cout << '\t' << a; // performance: most likely, compiler unrolls
// anyway...
std::cout << std::endl;
int x, y; // scope as local as possible...
std::cin >> x >> y;
// OK, I don't want to modify the loop variable, so I now use a duplicate...
int ii = i;
for(auto& a : ar) // I like the range based for loops...
// ^ reference this time is important, though!
{
if(a == x || a == y)
a = ii++;
}
}
if((n & 1) == 0)
{
// for even n, we have done one test too few!
// instead of duplicating the code, you might write a common function for...
std::cout << '?';
for(auto a : ar)
std::cout << '\t' << a;
std::cout << std::endl;
int x, y; // scope as local as possible...
std::cin >> x >> y;
for(auto& a : ar)
{
if(a == x || a == y)
{
a = n;
break; // just replace one!!!
}
}
}
}
Код, как указано выше, произведет 5 элементов для проверки. Помните, что мы исключили самое высокое значение (--n;
)? Теперь мы вернемся:
++n;
n
Теперь будет шестое значение, которое будет проверено, в дополнение к пяти оставшимся в массиве (если вам не нравится увеличивать и уменьшать, вы, конечно, можете поддерживать две переменные). Ты можешь использовать std::swap
обменять одно значение массива за другим.
Примечание: я лично предпочел бы больше C ++ — как std::array<int, 5> ar({1, 2, 3, 4, 5});
вместо необработанного массива, но это не большая проблема. Однако это облегчит передачу массива, если вы создадите его из дублирующего кода:
void f(std::array<int, 5> const& ar); // or non-const, if you want to replace inside, too
// or in more generic form:
template <size_t N>
void f(std::array<int, N> const& ar);
// vs.:
void f(int const(&ar)[5]);
// the more generic form:
template <size_t N>
void f(int const(&ar)[N]);
// or classical (and better known) pointer variant:
void f(int const* ar, size_t length);
Заключительные примечания:
if(!cin >> x >> y) { /* appropriate error handling */ }
), может быть, даже проверить допустимый диапазон впоследствии (например, ошибка, если x
а также y
равны или не совпадают ровно с одним значением в массиве — для последнего нам следует обратить внимание на несоответствие уже замененному значению).unsigned int
как тип данных. Но это не большая проблема, так что решайте сами …Других решений пока нет …