Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Поиск максимального размера подпоследовательности 
:(
    Опции темы
Сыроежка
Дата 7.7.2011, 18:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 127
Регистрация: 24.6.2011

Репутация: нет
Всего: 1



На одном форуме встретил такое задание для студентов: найти размер максимальной подпоследовательности, элементы которой возрастают по значению. То есть чтобы было понятно, то, например, если дан массив
Код


int a[] = { 1, 3, 4, 2, 7, 8, 9 };


то для него максимальной подпоследовательностью является { 2, 7, 8, 9 }, размер которой равен 4.

Любопытно, как решить эту простую задачу с помощью стандартныхъ алгоритмов? Естественно ее надо обобщить. 
Найти размер максимальной подпоследовательности, смежные элементы которой удовлетворяют некоторому предикату.
Кто-нибудь пытался решить эту задачу с помощью стандарнтных алгоритмов? У кого какие есть соображения?
PM MAIL   Вверх
Сыроежка
Дата 7.7.2011, 19:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 127
Регистрация: 24.6.2011

Репутация: нет
Всего: 1



И это еще не все. Допустим, вы каким-то образом с использованием стандартных алгоритмов нашли размер максимальной подпоследовательности, удовлетворяющей заданному критерию  в виду предиката. 
Но как теперь имея размер извлечь саму подпоследовательность? Стандартный алгоритм std::search_n не подходит, так как он ищет подпоследовательность заданной длины для фиксированного значения. К тому же предикату не передаются смежные элементы последовательности, а передается лишь заданное значение и значение очередного элемента последовательности.
PM MAIL   Вверх
borisbn
Дата 7.7.2011, 22:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



оно, конечно, можно, но предикат получился такой монстроидальный, что лучше, честно говоря ручками сделать - понятней будет
http://liveworkspace.org/code/83a72ae675f1...7913e88f95215b9


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
mes
Дата 7.7.2011, 22:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата

PridicatStorege 

бррр..  smile  smile 


--------------------
PM MAIL WWW   Вверх
borisbn
Дата 8.7.2011, 06:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



mes, ну, не без того - описался (ударение поставьте сами), а затем воспользовался передовой технологией копипаста smile

Кстати, там ошибище. Причём не описка, а именно в алгоритме. Переделывать не хочу. Лень smile

Это сообщение отредактировал(а) borisbn - 8.7.2011, 08:39


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
mes
Дата 8.7.2011, 09:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(borisbn @  8.7.2011,  05:17 Найти цитируемый пост)
а затем воспользовался передовой технологией копипаста 

ну при состовлении такого хитрого предиката вполне возможно не заметить .. уж больно он хитрый получился... 
мне кажется только, что Вы зря мучались, так как для adjacent_find в стл есть свой подходящий предикат..  smile 
правда абсолютно бесхитросный  : 
Код

for (auto f = arr.begin(); f != arr.end(); )
{
    auto  e = std::adjacent_find( f, arr.end(), std::greater<int>() );           
    if (e != arr.end()) ++e;
        
    for (auto it = f; it != e; ++it )     
       std::cout << *it << " ";    
    std::cout << " : ";      
           
    std::swap(f,e);                      
}
 http://liveworkspace.org/code/02f672d0356a...2bd3dedb0073cb1
smile 



Это сообщение отредактировал(а) mes - 8.7.2011, 11:04


--------------------
PM MAIL WWW   Вверх
borisbn
Дата 8.7.2011, 09:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



mes, да, но в задании требовалось
Цитата(Сыроежка @  7.7.2011,  18:04 Найти цитируемый пост)
найти размер максимальной подпоследовательности

и
Цитата(Сыроежка @  7.7.2011,  19:44 Найти цитируемый пост)
Но как теперь имея размер извлечь саму подпоследовательность?

да и цикл
Цитата(mes @  8.7.2011,  09:14 Найти цитируемый пост)
for (auto f = arr.begin(); f != arr.end(); )

уже не очень соответствует 
Цитата(Сыроежка @  7.7.2011,  18:04 Найти цитируемый пост)
Любопытно, как решить эту простую задачу с помощью стандартныхъ алгоритмов?


P.S. Критиковать всегда проще, чем предложить чего-нибудь smile Вот я по простому пути и пошёл  smile 


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
mes
Дата 8.7.2011, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(borisbn @  8.7.2011,  08:37 Найти цитируемый пост)
 да, но в задании требовалось

я не задание решал, а лишь показал что 
Цитата(mes @  8.7.2011,  08:14 Найти цитируемый пост)
для adjacent_find в стл есть свой подходящий предикат

 smile 

Цитата(borisbn @  8.7.2011,  08:37 Найти цитируемый пост)
 Критиковать всегда проще, 

ага, меня просто сильно "напугал" предикат, поэтому и отвлекся на критику..
smile
 


--------------------
PM MAIL WWW   Вверх
borisbn
Дата 8.7.2011, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(mes @  8.7.2011,  10:29 Найти цитируемый пост)
Критиковать всегда проще, 

вообще-то это я про себя говорил smile


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
Сыроежка
Дата 8.7.2011, 18:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 127
Регистрация: 24.6.2011

Репутация: нет
Всего: 1



Надо же, кто-то все-таки откликнулся!

Естественно, первое, что приходит в голову, это использовать два ключевых  шага. 
Первый - это вызов std::adjacent_find с предикатом, как, например,  std::greater<value_type>.

Примечение:
Код

 typedef typename std::iterator_traits<ForwardIterator>::value_type value_type


А затем во-втором шаге использовать std::find_if с отрицанием данного предиката, то есть использовать адаптер std::not1.

Я так и сделал, и у меня получился достаточно изящный пользовательский алгоритм.

Но проблема состоит в том, что этот алгоритм выдает не совсем то, что требуется. То есть, например, для последовательности

Код

int a[] = { 1, 3, 5, 2, 6 }; 


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

Ежели строго следовать заданию, то максимальная подпоследовательность - это всего лишь { 1, 3, 5 }, так как 2 уже расположена не по возрастанию после 5.

То есть получается, что такую простую задачу с помощью существующего набора стандартных алгоритмов не решить.  

Еще хуже дело обстоит, когда мы знаем размер максимальной подпоследовательность и хотим ее получить по искомому размеру. Алгоритм std::search_n для этих целей не подходит, так как он вызывает предикат не для смежных элементов, чтобы их можно было сравнить, а лишь для текущего значения итератора и заданного константного значения.

Я  сегодня с утра посидел за компьютером и в конечном итоге состряпал 40 разновидностей алгоритма adjacent_find!smile В большинстве своем они представляют из себя некоторые адаптеры стандартных алгоритмов  При этом в этот набор не входят алгоритмы, которые ищут не просто первый элемент из смежных элементов в последовательности, а весь диапазон смежных элементов.


PM MAIL   Вверх
Сыроежка
Дата 8.7.2011, 19:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 127
Регистрация: 24.6.2011

Репутация: нет
Всего: 1



Цитата(borisbn @  7.7.2011,  22:28 Найти цитируемый пост)
оно, конечно, можно, но предикат получился такой монстроидальный, что лучше, честно говоря ручками сделать - понятней будет
http://liveworkspace.org/code/83a72ae675f1...7913e88f95215b9 


Спасибо. ВЫ своим кодом меня позабавили! Ваш код в десятки раз сложнее, чем условие задания.

Замечу лишь, что проще написать свой алгоритм

Код

template <typename ForwardIterator,
                 typename BinaryPredicate>

std::pair<ForwardIterator, ForwardIterator> adjacent_range( ForwardIterator first,
                                                                                                   ForwardIterator last,
                                                                                                   BinaryPredicate binary_predicate );


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

Что касается вашего кода, то лишь замечу, что код (раз уж речь зашла об алгоритмах)

Код

for ( int i = 0; i < a_count; i++ )
{
   cout << arr[ i ] << " ";
}
 cout << endl;

    
можно заменить на выхов алгоритма std::copy

Код

std::copy( arr, arr + a_count, std::ostream_iterator<int>( std::cout, " " ) );

 




Это сообщение отредактировал(а) Сыроежка - 8.7.2011, 19:12
PM MAIL   Вверх
Qu1nt
Дата 8.7.2011, 19:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 1
Всего: 50



Сыроежка, покажите же свою реализацию!
PM MAIL   Вверх
Сыроежка
Дата 8.7.2011, 19:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 127
Регистрация: 24.6.2011

Репутация: нет
Всего: 1



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

Код

template <typename ForwardIterator,
                 typename BinaryPredicate>

typename std::iterator_traits<ForwardIterator>::difference_type max_adjacent_seq( ForwardIterator first,
                                                                                                                                        ForwardIterator last,
                                                                                                                                        BinaryPredicate binary_predicate )
{
   typedef typename std::iterator_traits<ForwardIterator>::value_type value_type;
   typedef typename std::iterator_traits<ForwardIterator>::difference_type difference_type;

   difference_type max = 0;
   std::pair<ForwardIterator, ForwardIterator> p;

   for ( ; first != last; first = p.second )
   {
      p.first = std::adjacent_find( first, last, binary_predicate );



Увы, у меня сейчас время закончится. Я вам скорей всего завтра приведу полный цикл. Просто интересно использование отрицание бинарного предиката для поиска конца последовательности.

Код

std::not1( std::bind1st( binary_predicate, *p.first ) )


Завтра весь код покажу. Он достаточно прост и изящен. А для решения задачи в строгом соответсвии с условием я просто, как уже отметил, написал свой алгоритм adjacent_ordered_range, вместо использования adjacent_find и find_if/ 
PM MAIL   Вверх
mes
Дата 9.7.2011, 01:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Сыроежка @  8.7.2011,  17:20 Найти цитируемый пост)
он выдаст значение 5, то есть включит в максимальную подпоследовательность всю последовательность, так как все элементы после первого больше по значению, чем первый элемент.

Ежели строго следовать заданию, то максимальная подпоследовательность - это всего лишь { 1, 3, 5 }, так как 2 уже расположена не по возрастанию после 5.

То есть получается, что такую простую задачу с помощью существующего набора стандартных алгоритмов не решить.  

чего то Вы намутили ?! все нормально должен искать, так как сравнение идет соседних элементов, а не с первым.. 

Цитата(Сыроежка @  8.7.2011,  18:36 Найти цитируемый пост)
 Просто интересно использование отрицание бинарного предиката для поиска конца последовательности.

а зачем загромаждать себя лишним not`ом ? или это иследовательский энтузиазм ?


--------------------
PM MAIL WWW   Вверх
Сыроежка
Дата 9.7.2011, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 127
Регистрация: 24.6.2011

Репутация: нет
Всего: 1



Итак, на чем я остановился? Ранее я уже набрал

    
Код

template <typename ForwardIterator,
          typename BinaryPredicate>
typename std::iterator_traits<ForwardIterator>::difference_type max_adjacent_seq( ForwardIterator first,
                                                                                  ForwardIterator last,
                                                                                  BinaryPredicate binary_predicate )
{
   typedef typename std::iterator_traits<ForwardIterator>::value_type value_type;
   typedef typename std::iterator_traits<ForwardIterator>::difference_type difference_type;
   difference_type max = 0;
   std::pair<ForwardIterator, ForwardIterator> p;
   for ( ; first != last; first = p.second )
   {
      p.first = std::adjacent_find( first, last, binary_predicate );


Здесь лишнее определение типа value_type. Оно не используется. Поэтому выкидываем его

Код

template <typename ForwardIterator,
          typename BinaryPredicate>
typename std::iterator_traits<ForwardIterator>::difference_type max_adjacent_seq( ForwardIterator first,
                                                                                  ForwardIterator last,
                                                                                  BinaryPredicate binary_predicate )
{
   typedef typename std::iterator_traits<ForwardIterator>::difference_type difference_type;

   difference_type max = 0;
   std::pair<ForwardIterator, ForwardIterator> p;
   for ( ; first != last; first = p.second )
   {
      p.first = std::adjacent_find( first, last, binary_predicate );


Теперь продолжим

Код

template <typename ForwardIterator,
          typename BinaryPredicate>
typename std::iterator_traits<ForwardIterator>::difference_type
max_adjacent_seq( ForwardIterator first,
                  ForwardIterator last,
                  BinaryPredicate binary_predicate )
{
   typedef typename std::iterator_traits<ForwardIterator>::difference_type difference_type;

   difference_type max = 0;
   std::pair<ForwardIterator, ForwardIterator> p;

   for ( ; first != last; first = p.second )
   {
      p.first = std::adjacent_find( first, last, binary_predicate );
      p.second = last;

      if ( p.first != p.second )
      {
         ForwardIterator next = p.first;
         p.second = std::find_if( ++next, p.second,
                                               std::not1( std::bind1st( binary_predicate, *p.first ) ) );
         difference_type size = std::distance( p.first, p.second );
         if ( max < size ) max = size;
      }
   }

   return ( max );
}


Если я ничего не напутал, то получился изящный профессионально написанный алгоритм. Можете этот алгоритм от Сыроежки положить в свою копилку алгоритмов. Если его запускать с адаптером std::equal_to, то действительно можно получить размер максимальной последовательности смежных элементов.

Однако, как я уже заметил выше, для адаптеров типа  std::greater или std::less мы получим не возрастающую или убывающую по значению последовательность смежных элементов, а последовательность смежных элементов, каждый элемент которой больше/меньше  первого элемента. Это не ошибка кода, а результат того, что есть два подхода. Либо смежными считать все эелементы, которые удовлетворяют предикату, когда первым аргументом при вызове предиката является значение первого элемента. Либо смежными считать последовательность, все элементы которой попарно удовлетворяют предикату.

И проблема состоит в том, что без написания собственного алгоритма для поиска диапазона упорядоченнных смежных элементов, эту проблему не решить.

Если написать такой алгоритм, то вышеприведенный алгоритм естественно сильно упрощается.

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1020 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.