Задача динамического программирования.

Может ли кто-нибудь помочь мне найти оптимальный алгоритм динамического программирования для этой проблемы

По пути на ужин участники CCC выстраиваются в очередь за вкусным кудрявым картофелем фри. N (1 ≤ N ≤ 100) участников выстроились в колонну, чтобы войти в столовую.

Доктор В., руководитель CCC, в последний момент понял, что программисты просто ненавидят стоять в очереди рядом с программистами, использующими другой язык. К счастью, в CCC разрешены только два языка: Gnold и Helpfile. Кроме того, участники решили, что они войдут в столовую только в том случае, если они входят в группу не менее чем из K (1 ≤ K ≤ 6) участников.

Доктор В решил повторить следующую схему:

* He will find a group of K or more competitors who use the same language standing next to each other in line and send them to dinner.
* The remaining competitors will close the gap, potentially putting similar-language competitors together.

Итак, Доктор Ви записал для вас последовательность участников. Могут ли все участники пообедать? Если да, то какое минимальное количество групп участников можно отправить на ужин? Вход

Первая строка содержит два целых числа N и K. Вторая строка содержит N символов, которые представляют собой последовательность участников в строке (H представляет Helpfile, G представляет Gnold) Выходные данные

Выведите в одной строке единственное число — минимальное количество групп, которые формируются к обеду. Если не все программисты могут пообедать, выведите -1.


person GEP    schedule 04.03.2011    source источник
comment
Вероятно, вам следует пометить вопрос соответствующим образом, если вы хотите получить ответы. trick — очень бессмысленный тег.   -  person Felix Kling    schedule 04.03.2011
comment
@kletoskletos - Есть ли причина использовать здесь динамическое программирование? Поскольку нам дано количество программистов Helpfile и количество программистов Gnold, мы можем разделить их количество на номер группы, указанный Доктором В. Оставшихся программистов в любой группе нужно добавить в уже сформированную группу, чтобы она не t превышают группы из шести. Думаю, именно здесь в игру вступает динамическое программирование. Интересная проблема.   -  person sc_ray    schedule 04.03.2011
comment
@sc_ray: я думаю, вы неправильно поняли проблему. Вам нужно найти смежные группы из не менее K человек и удалить их из очереди таким образом, чтобы в конечном итоге вы могли удалить всех людей из очереди. Вы не можете изменить порядок очереди, вы можете только удалить группы программистов-единомышленников, которые случайно оказались рядом друг с другом.   -  person Null Set    schedule 04.03.2011
comment
@Null Set: В таком случае, как бы вы сгруппировали следующую последовательность GHHGHHGH для K›=2?   -  person sc_ray    schedule 04.03.2011
comment
@sc_ray - вы бы не напечатали -1.   -  person IVlad    schedule 04.03.2011
comment
Таким образом, в основном проблема сводится к поиску самой длинной подстроки с общими символами, но для таких последовательностей, как GHHGHHG, где G изолированы, нам нужно найти все G, пока не будет достигнут предел группы?   -  person sc_ray    schedule 04.03.2011


Ответы (3)


Я бы предпочел не решать проблему SPOJ на практике для вас, поэтому примите следующее как доказательство существования поливременной DP.

Для фиксированного K набор строк, которые могут обедать, не зависит от контекста. Я собираюсь использовать g и h вместо G и H. Например, для K = 3 одна грамматика выглядит так

S -> ε | g S g S g S G | h S h S h S H

G -> ε | g S G

H -> ε | h S H

Идея состоит в том, что либо обедающих нет, либо первый обедающий обедает не менее чем с K - 1 другими, между любыми двумя из которых (и последним, и конечным) есть цепочка, которая может обедать.

Теперь используйте взвешенный вариант CYK, чтобы найти синтаксический анализ минимального веса, в котором непустые S-продукции имеют вес. 1, а все остальные имеют вес 0. При фиксированном K время работы CYK равно O(N3).

person user635541    schedule 06.03.2011
comment
Итак, вы говорите, что я могу решить проблему за время O (kN ^ 3), используя общую версию алгоритма CYK. - person GEP; 07.03.2011
comment
Да, размер грамматики линейен по k после преобразования в нормальную форму Хомского. - person user635541; 07.03.2011
comment
Проблема в том, что я не знаю, что такое нормальная форма Хомского и как ее преобразовать. На самом деле я впервые вижу этот алгоритм CYK, но он очень похож на алгоритм умножения цепочки матриц. На самом деле я думал об алгоритме, который находит оптимальное решение со всеми возможными оставшимися обедами и объединяет их. Основой является алгоритм умножения цепочки матриц, и он требует дополнительного времени O (n ^ 2) для каждого ve в общей сложности O (n ^ 5). Можете ли вы дать лучшее описание вашего алгоритма снизу вверх? - person GEP; 07.03.2011
comment
Нормальная форма Хомского описана в Википедии. Идея состоит в том, чтобы правая часть каждой продукции была либо не более чем одним терминалом, либо ровно двумя нетерминалами. Наивная версия CYK, по сути, проверяет, может ли каждая из подстрок O (n ^ 2) быть создана каждым нетерминалом. Случай с двумя нетерминалами требует, чтобы алгоритм угадывал среднюю точку. - person user635541; 08.03.2011

Подзадача — минимальные группы, необходимые для того, чтобы все обедали при заданном состоянии очереди. Существует множество возможных состояний строк, но только некоторые из них будут видны на самом деле, поэтому вам, вероятно, следует выполнять запоминание с помощью хэш-карты.

Вот какой-то псевдокод.

int dine(string line){
    if(hashmap.contains(line)){
        return hashmap.get(line);
    }
    if(line.length == 0){
        return 0;
    }
    best = N+1;
    for(i=0;i<line.length;i=j){
        type = string[i];
        j = i+1;
        while(type == string[j]){
            j++;
        }
        if(j-i >= K){
             result = dine(string.substring(0,i-1) + string.substring(j,string.length));
             if(result > 0 && result < best){
                  best = result;
             }
        }
    }
    if(best == N+1){
         hashmap.insert(line, -1);
         return -1;
    }
    else {
         hashmap.insert(line, best+1);
         return best+1;
    }
}

Если вы уже нашли ответ для этой строки, верните этот ответ. Если в очереди нет людей, вы уже закончили и вам не нужно формировать группы.

Предположим, вы не можете формировать какие-либо группы. Затем попытайтесь доказать, что это не так, попробовав все смежные группы программистов-единомышленников в очереди. Если группа достаточно велика, чтобы ее можно было выбрать, посмотрите, сколько еще действий потребуется, чтобы собрать всех в ресторане после удаления этой группы. Следите за наименьшим количеством необходимых движений.

Если вы не можете найти способ удалить все группы, верните -1. В противном случае верните наименьшее количество ходов, необходимых после удаления группы, плюс один, чтобы учесть ход, сделанный на этом шаге.

person Null Set    schedule 04.03.2011
comment
Можете ли вы указать сложность вашего решения и еще несколько объяснений? - person GEP; 04.03.2011
comment
@dosdos Понятия не имею о сложности. - person Null Set; 04.03.2011
comment
Я считаю, что ваше решение может стать экспоненциальным со временем. - person GEP; 04.03.2011
comment
Я думаю, что это экспоненциально. Рассмотрим строку типа HGHGHGHG... длиной 100 и k = 1. Я думаю, что это сделает много рекурсивных вызовов. - person IVlad; 04.03.2011
comment
@IVlad Я думаю, что вы можете быть правы, но я чувствую, что нет другого способа сделать это как DP, который всегда даст оптимальный ответ. Порядок, в котором вы выбираете группы, важен, например, с HHGGHH, K = 2. Существует двухходовое решение и 4 трехходовых решения. - person Null Set; 04.03.2011
comment
Я реализовал это на C#, используя Dictionary для хеша, и для строки из 40 символов, созданной, как я сказал в предыдущем комментарии, требуется очень много времени. Должен быть способ сделать это, многие люди решили это на SPOJ. Впрочем, я тоже пока не вижу. - person IVlad; 04.03.2011
comment
@Null Set - ну, мы говорим о создании 2 ^ N наборов для N элементов и последующем извлечении нескольких подмножеств. Я почти уверен, что для неограниченных входных данных это будет решаемо за экспоненциальное время. - person sc_ray; 04.03.2011
comment
Я думаю об алгоритме, похожем на умножение цепочки матриц, но я не уверен, что он правильный. - person GEP; 05.03.2011

Как насчет разделяй и властвуй? Возьмите (съемную) группу где-то ближе к середине, а две группы по бокам от нее, скажите ...HHHGGGGGHHHHH.... - теперь есть две возможности. Либо эти 2 набора H обедают в одной группе, либо нет. Если они обедают в одной группе, то эти G между ними должны быть удалены как группа точно этих G (поэтому вы можете попробовать это в качестве первого хода). Если нет, то вы можете найти левый и правый подсписки отдельно. В любом случае у вас есть более короткий список для рекурсии.

person Chris Nash    schedule 04.03.2011
comment
Да, но какова временная сложность этого алгоритма? - person GEP; 05.03.2011
comment
Я думаю, что, возможно, проще было бы сказать, что вы пытаетесь отметить первый и последний элементы каждого удаления. Я уверен, что у него есть потенциал быть экспоненциальным, но я не думаю, что есть какой-то способ обойти это (вы можете построить некоторые последовательности для наихудшего случая), но, надеюсь, ваш вклад в конкуренцию будет добр :) - person Chris Nash; 05.03.2011
comment
На самом деле я думал об алгоритме умножения цепочки матриц, который работает так. - person GEP; 05.03.2011
comment
Сожмите исходную последовательность, подобную этой HHHGGHHH, в 3 2 3, а затем найдите оптимальный способ для каждой возможной комбинации, такой как умножение цепочки матриц. Это работает для случаев, которые я пробовал, но я не уверен, что это работает в целом - person GEP; 05.03.2011
comment
Это отличная проблема. Мне было бы очень интересно посмотреть, что такое «умное» решение. - person Chris Nash; 05.03.2011