Комментарии 55
2. выкидываем 4, которые оказались легче.
3. кладем оставшиеся 4 шарика на весы по 2 на каждую чашу.
4. убираем по одному шарику с каждой чаши, выкидывая тот, что был взят с более легкой чаши.
5. в зависимости от от того, как изменится баланс весов, нужный шарик будет тот, который либо остался на более тяжелой чаше, либо окажется в руках.
Можно обойтись двумя.
2. если чаши равны, то искомый шарик в оставшихся двух
3. если не равны, то выкидываем три самых легких
4. взвешиваем 2 из оставшихся трех — задача решена :)
В целом из задач только над 3 можно подумать. Остальные явно на позицию юниора не выше. Ну или во 2 искать точную формулу и пытаться убрать цикл (а возможно ли это?).
Доллар даёт одну шоколадку; шоколадка даёт одну обертку; одна обёртка даёт 1/3 шоколадки.
Тогда, при условии, что у нас бесконечное количество долларов, мы за каждый доллар получим:
1 + 1/3 + 1/9 + 1/27… шоколадок. Это убывающая геометрическая прогрессия. Если посчитать её сумму, то получим 1.5 шоколадки за каждый потраченный доллар.
Однако, у нас не бесконечное количество долларов. Для того, чтобы узнать, сколько шоколадок мы получим за один доллар, достаточно узнать, на каком шаге вычисления прогрессии мы остановимся:
x<=3: 1
3<x<=9: 1 + 1/3
9<x<=27: 1 + 1/3 + 1/9
…
Тогда решение задачи для примера из условия выглядит так:
x = 25
3^1 = 3 < x
3^2 = 9 < x
3^3 = 27 > x => нужно вычислить три шага
1 + 1/3 + 1/9 = 13/9
Теперь просто перемножаем: 15 * 13/9 = 21,6666666 ~ 21 (округляем всегда в меньшую сторону). Решение можно представить в обобщенном виде для любых «money, price, wrap».
Приведите, пожалуйста, пример, где указанный вами выше подход не работает? Как один пример, когда формула работает: возьмем 14 уе, тогда 14*13/9=20.2(2), в ручную: 14 + 4 (две обертки в остатке) + 2 (2 обертки остатка, 4 обертки от второй партии) = 20.
На первой итерации каждый потраченный доллар гарантированно принесёт нам 1/price шоколадок. На второй: 1/price*wrappers и так далее. Снова получается геометрическая прогрессия. Первый шаг не зависит от wrappers, поэтому в прогрессию мы его не включаем. Теперь нужно посчитать s(n), — где n — это степень, при которой wrappers^n >= workMoney (по-хорошему, здесь должно быть просто «больше», но из-за потери точности даже в Decimal и округления вниз в некоторых ситуациях получается число вроде 47.9999999996 вместо 48), a0 = 1/wrappers * price.
Финальный шаг: сложим 1/price и s(n) и умножим на workMoney. Округляем в меньшую сторону.
Примеры:
money = 15, price = 1, wrappers = 3
workMoney = 15
n = 3, s(3)=1/3 + 1/9 + 1/27 = 14/27 ~ 0.4815
1 + 0.4815 = 1.4815
result = 15 * 1.4815 ~ 22.22 = 22
money=17, price = 3, wrapers = 5
WorkMoney = 15
n = 2, s(2) = 1/5*3 + 1/25*3 = 1/15 + 1/75 = 7/75
1/3 + 7/75 = 32/75 ~ 0.427
result = 15 * 0.427 ~ 6,3 = 6
Код:
private static int ChocolateCount(int money, int price, int wrappersPerOneChoco)
{
var workMoney = money - (money % price);
var stepsCount = 0;
int wrappers = 1;
while (wrappers <= workMoney)
{
stepsCount++;
wrappers = wrappers * wrappersPerOneChoco;
}
var chokosPerDollar = 1 / (double)price;
var additionalChokosByCurrentStep = 1 / (double)price;
for (int i = 0; i < stepsCount; i++)
{
additionalChokosByCurrentStep = additionalChokosByCurrentStep / wrappersPerOneChoco;
chokosPerDollar = chokosPerDollar + additionalChokosByCurrentStep;
}
return (int) (workMoney * chokosPerDollar);
}
Но ведь ответ не 21, а 22.
15 долларов == 15 шоколадок.
15 оберток == 5 шоколадок. (нарастающий итог == 20)
5 оберток == 1 шоколадка и 2 обертки (нарастающий итог == 21)
1 обертка от шоколадки и 2 обертки с пред. шага == 1 шоколадка (итог == 22).
public static int calcChocoCount(int money, int price, int wrap){
int chocoByMoney = money/price;
return chocoByMoney + (chocoByMoney-1)/(wrap-1);
}
или весики уравновесятся или будет перевес
1.1 если уравновешены — значит тяжелый шарик один из двух оставшихся, просто взвешиваем их, находим нужный
1.2 если какие-то три перевесили, снова взвешиваем любые 2 из них
1.2.1 если весы уравновешены — тяжелый третий из этой выборки
1.2.2 если весы уехали — ниже тяжелый
Получили за 2 взвешивания
Но больше всего смущает ускорение свободного падения. При нормальном ускорении он бы 10 метров пролетел за секунду с небольшим. А √2 это 1.414 примерно, так где он по пути задержался? Но опять же не сказано, что он мог по пути что-то задевать.
А еще можно сказать, что и бурые, и белые медведи с черной кожей, поэтому они черные!
В любом случае вопрос мне кажется довольно странным.
int total_chocolate_count(int money_, int price_, int wrap_) {
int total_count = money_ \ price_;
int prev_count = total_count;
do {
total_count += prev_count \ wrap_;
prev_count = prev_count \ wrap_ + prev_count % wrap_;
}
while (prev_count \ wrap_ == 0)
return total_count;
}
За 1 доллар можно купить 1 1/3=4/3 шоколадки, за 15 долларов — 15*4/3=20 шоколадок. 2 фольги можно превратить в шоколадку: показать их продавцу и попросить шоколадку, которая будет тут же съедена и все 3 фольги отданы продавцу
Хотя вроде бы в чистом C, если не ошибаюсь, сих пор нет массивов и задачка предполагает что человек быстро накидает алгоритм сортировки байтиков?
Задача решается без массивов :)
А уж решение с сортировкой 100% будет завернуто как неэффективное.
Прошу прощения, если вопрос глупый, я больше ит-менеджер и программированием интересуюсь только контексте автоматизации рутинных задач.
Но ведь для определения кто из них меньший, а кто больший, мы уже должны иметь все цифры на руках?Да, должны. Но нам не обязательно их в массив сохранять, можем просто пробежаться циклом, экономия памяти выйдет. Представьте, например, что мы получаем 1 млрд 64-битных чисел по сети и из них нужно найти минимум. Просто сохранить их в массиве займет ~8 гб оперативной памяти, а пробежаться по ним циклом займет три переменных.
Ну а насчет сортировки — она делается за O(NlogN), что гораздо дольше, чем O(N).
Провел эксперимент:
Пусть у нас есть
unsigned long long generator() {
static unsigned long long x = 0; // Предыдущее сгенерированное число
return x = x * 239017u + 170239u; // Текущее сгенерированное число
}
double start = clock(); // Запоминаем момент начала
std::vector<unsigned long long> numbers; // Массив для чисел
numbers.reserve(SIZE); // Выделяем память, без этого будет работать дольше
std::generate_n(std::back_inserter(numbers), SIZE, generator); // Генерируем 1 млрд чисел
std::sort(numbers.begin(), numbers.end()); // Сортируем
std::cout << numbers[0] << ' ' << numbers[SIZE - 1] << std::endl; // Выдаем ответ
std::cout << (clock() - start) / CLOCKS_PER_SEC << std::endl; // Выдаем время
На моем ноутбуке этот код использует 7.6 ГБайт оперативной памяти и работает за 187 секунд.double start = clock(); // Запоминаем момент начала
std::vector<unsigned long long> numbers; // Массив для чисел
numbers.reserve(SIZE); // Выделяем память, без этого будет работать дольше
std::generate_n(std::back_inserter(numbers), SIZE, generator); // Генерируем 1 млрд чисел
auto mm = std::minmax_element(numbers.begin(), numbers.end()); // Находим минимум и максимум
std::cout << *mm.first << ' ' << *mm.second << std::endl; // Выдаем ответ
std::cout << (clock() - start) / CLOCKS_PER_SEC << std::endl; // Выдаем время
На моем ноутбуке этот код использует 7.6 ГБайт оперативной памяти и работает за 9 секунд.double start = clock(); // Запоминаем момент начала
unsigned long long min = std::numeric_limits<unsigned long long>::max();
unsigned long long max = std::numeric_limits<unsigned long long>::min();
for (int i = 0; i < SIZE; ++i) { // Цикл по всем числам
unsigned long long x = generator(); // Генерируем очередное число
min = std::min(min, x); // Обновляем минимум
max = std::max(max, x); // Обновляем максимум
}
std::cout << min << ' ' << max << std::endl; // Выдаем ответ
std::cout << (clock() - start) / CLOCKS_PER_SEC << std::endl; // Выдаем время
На моем ноутбуке этот код использует 6 МБайт оперативной памяти и работает за 1.5 секунды.Хотя вроде бы в чистом C, если не ошибаюсь, до сих пор нет массивов и задачка предполагает что человек быстро накидает алгоритм сортировки байтиков?
Взвешиваем любые 3 и 3. Если они одинаковые, то взвешиваем оставшиеся 2. Находим тяжелый.
Если одна из троек тяжелее, то взвешиваем два шарика из «тяжелой» тройки. Любые. В результате искомый шар будет или одним из двух, или оставшимся, не взвешенным.
1 обертка == 1/3 шоколадки. :)
Задача с произведением мин-макс меня вгоняет в ступор. Если там нет дополнительных ограничений, и в задаче нужно найти минимальный элемент, максимальный элемент, и просто перемножить, то смысла в задаче не вижу.
Задача с 2 компами вероятно дана для общения между кандидатом и принимающей стороной. В этом задаче нет некоторых пояснений, например какой объем дополнительной памяти можно использовать и какой приоритет (время работы, простота алгоритма, время написания кода). Есть ли смысл выкладывать сюда задачи такого типа, если автор не может выступить полноценно второй стороной?
Решения мои
Вопрос 2.

Задача 1. Решение слишком очевидно, чтобы его приводить.
Задача 2. Там тоже все просто, переводим бабло в шоколадки. А дальше в цикле переводим шоколадки в обвертки, а их опять в шоколадки по курсу.
Задача 3.
Предположим, что у нас уже есть 2 компа с уже отсортированными (на каждом из них) данными. В цикле проходим по обоим массивам на первой машине начинаем с начала, а на второй с конца. Рано или поздно число в на первой машине станет меньше числа на второй. Вот мы и нашли ту границу, по которой нужно числа со второго компа отправлять на первый, и наоборот. Могу написать алгоритм, который без дополнительной памяти (ну несколько переменных) путем замены ячеек сделает из двух упорядоченных массивов один за линейное время.
Но если мы можем это сделать(из 2-х упорядоченных сделать один), то автоматом решается и все предыдущие этапы задачи. Т.е. сначала разбиваем весь массив на пары и упорядочиваем. Затем пары объединяем в четверки, их уже в 8-ки и так далее, пока не получим цельный алгоритм. Если алгоритм слияния линейный, тогда сложность всего алгоритма — N*ln2(N).
С другой стороны можно пройтись по всему не отсортированному массиву, посчитать кол-во значений у которых первый бит =1. Зная это значение, можно перенести такие значения вверх, а оставшийся вниз. Хотя наверное, для этого даже считать их кол-во не нужно, нужно только знать границы массива. Далее в каждом из получившихся групп проводим сортировку по второму биту и так далее. Каждая операция сортировки по биту выполняется за O(n). Итого на подготовительную операцию уходит O(N*ln2(M)), где M — это максимальное значение типа, а ln2(M)- количество бит. И пусть M>N, но разница не большая, и будет важна константа алгоритмической сложности.
Надо будет посмотреть, сколько займет на этих данных пузырьковая сортировка, ради интереса.
Выпуск#7: ITренировка — актуальные вопросы и задачи от ведущих компаний