Не знаю, как правильно решить следующую задачу. Есть идеи, но они не проходят. Кто знает, направьте в верное русло, пожалуйста. Также, если знаете похожие задачи, то поделитесь ссылками на них. Оригинальная формулировка задачи с тестами доступна здесь
Во входном файле до 50 тестов. Каждый тест — отдельная подзадача. Нужно вывести ответ для каждой подзадачи с новой строки. Подзадача состоит в следующем:
На нашем пути есть от 1 до 20 засад, в каждой засаде сидят k[i] разбойников (от 1 до 1000), чтобы они нас пропустили, нужно c[i] монет (от 1 до 1000). Изначально в нашем отряде 0 наемников.
Мы можем:
Нанять бандитов, сидящих в засаде, потратив 2 * c[i] монет
Заплатить бандитам c[i] монет, чтобы они нас пропустили
Сразиться с ними. Погибает одинаковое количество с обеих сторон. Причем у нас те наемники, которые были наняты раньше, погибают первыми. Но наемники не выдерживают больше трех битв. После третьей битвы они уходят от нас, если выживают.
Необходимо проехать все засады, потратив наименьшую сумму денег. В ответ выдать эту сумму денег.
Ограничения: 3 секунды, 256 МБ на тест, таким образом, 0.06 секунд и 256 МБ на одну подзадачу.
Думал в сторону двумерного ДП. Параметры:
количество пройденных засад
набранная сумма
Для состояния dp[k][sum] хранить оптимальную тройку (n1, n2, n3) — сколько наемников могут участвовать в одной битве, двух и трех соответственно. Для недостижимых позиций ( - 1, - 1, - 1). Но не ясно, как выбирать из двух возможных троек лучшую при одинаковых переходах. Если выбирать по сумме, то тройка (1000, 0, 0) окажется лучше тройки (0, 0, 999). но все наемники убегут после первой битвы. Если выбирать по компонентам, то (0, 0, 2), окажется лучше, чем (999, 0, 1), но тогда не победить 1000 разбойников. Поэтому вариант с тройками не проходит, а больше адекватных идей нет.
Выгодно ли нам вообще нанимать бандитов? Ведь если я правильно понял задачу, заплатив
2*x
мы получаем возможность в лучшем случае преодолеть ещеx
последующих бандитов бесплатно, что в лучшем случае эквивалентно тому, что мы заплатим всем этим бандитам за то, чтоб они нас пропустили те же2*x
денег. А потому мы просто можем никого не нанимать и заплатить всем — в таком случае ответом на каждый тест будет просто сумма массива и DP не нужно.Нет, не так. У каждых бандитов своя стоимость покупки и свое количество. То есть, для засад i и j стоимость прохода задана в тесте как c[i] и c[j] (могут не совпадать), а количество бандитов k[i] и k[j] (могут не совпадать).
К посту добавил оригинальную формулировку задачи с примерами входных / выходных данных
Автокомментарий: текст был обновлен пользователем dmkz (предыдущая версия, новая версия, сравнить).
Можно хранить в состоянии суммарное число нанятых бандитов(а сумму видимо ответом динамики). Мы всегда знаем, что это последние бандиты, которых можно было нанять (почему?). То есть по факту нужно решать как будто без ограничения на кол-во бандитов, но при этом при каждом k делать
bandits = min(bandits, K[k] + K[k - 1] + K[k - 2])
Если я правильно вас понял, то вот тест, где не 3 последних группы выгоднее всего нанимать:
Да, понял в чем проблема.
А если дополнительно к количеству хранить маску длины 3, где мы кого-то нанимали? А таком случае нужно всегда тратить их жадно со старых, а значит вроде понятно, сколько человек пропадает при переходе
Возможно, я что-то не понял в идее решения, но вот тест:
Нужно собрать все 5 первых групп, чтобы побить последнюю (на мораль наёмников влияют только бои).
А, я неправильно понял условие:(
Auto comment: topic has been translated by dmkz (original revision, translated revision, compare)
Auto comment: topic has been updated by dmkz (previous revision, new revision, compare).
struct orcState {
Can you describe the algorithm with the orcs (bandits) states in details for evaluate complexity of solution? Naive with states for each groups get TLE because 320 = 3486784401 is very large number of states.
The following C++17 solution may have a reasonable execution time.
The following Solution seems to have a reasonable execution time.
Starting with a set of candidate partial solutions that contains a null initial state and an INT_MAX upper bound for the minimum cost, the required solution is the value of the upper bound when the set of partial solutions is empty. The iterative progress through the groups adds a new partial solution to the set only if its present cost is less than the present upper bound.
Hope that this helps.
Beautiful code style! But this is not full solution.
WRONG ANSWER: This counter-test — WA is 7, but true answer is 6:
TIME LIMIT EXCEEDED: This counter-test takes greater then one minute (65.959 sec) — TLE. In this test, each of the 50 sets of input data is different.
This problem from coding interview in Samsung company.
I don't know how to solve it normal, but wrote the same brute O(3n). It isn't TLing for 50 random testcases you provided, also works on samples. I believe, that this solution may works quite good on random testcases, but can be hacked with some special situations.
https://ideone.com/qAsgd6
Thanks! This is simple TLE test. We get TLE when we can fight with each group from each state.
Maybe normal solution is recursion with memoization or partial memoization or dynamic programming over subsets. Maybe there are very few very worst tests, and we can make a preliminary calculation.
edited!
Nice! This is not O(3n), because in the sequence of actions, a word "fight" can not be contained more than three times in a row.
1.340.895.616 in worst case if we not hire last group, not fight with first group and not fight more than 3 times in row
Comment below. It's will works bad (O(3n)), when solution is hire all, but fight last.
On test
your code gives incorrect answer 1003 (because you modify variables
orc1, orc2, orc3
when you choose "fight" option, but you then use new values instead of old in other options). After fixing this bug, your code works >2s on my computer on this single test:And shuffling transition order won't help, because answer is 38 and it is impossible to spend more than 38 coins on first 19 operations no matter what you do, so you never actually cut any useless branches.
3.46 sec and 1 327 729 094 calls on this single test after fix bug
Thanks for the kind words.
For the first counter-test, replacing
set< state_t >
in line 48 withmultiset< state_t >
generated the expected output.The second counter-test with TLE result requires further checking.