Программирование игр и головоломок - [61]

Шрифт
Интервал

.

Чтобы навести себя на правильный путь, заметьте, что если верхние элементы спускаются на m полей, то нижние элементы поднимаются на nm полей.

Вы не видите? Есть n полей. Вы работаете в арифметике по модулю n. По модулю n все элементы спускаются на m полей. На этот раз вы должны найти решение, учитывая влияние на ход решения наибольшего общего делителя m и n[26]

Головоломка 34.

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

Следовательно, Предположим, что мы прошли таблицу до номера i включительно. Пусть в пройденной части мы нашли, что элемент со значением x повторялся p раз, и пусть это — максимальное число повторений.

Но нужно еще более уточнить ситуацию в точке остановки. У нас есть две возможности.

— Первая идея: мы останавливаемся в конце равнинного участка.

Если i = n, то мы прошли всю таблицу, узнали наилучший равнинный участок, и все закончено. В противном случае мы пробегаем следующую равнину и измеряем ее длину r. Если rp, то наилучшая равнина остается неизменной, а в противном случае именно последняя равнина и регистрируется заново как наилучшая, и мы возобновляем движение по таблице. Это просто, и это легко программировать. Запишите это решение, чтобы иметь возможность сравнить его с другими решениями.

— Вторая идея: мы останавливаемся в произвольной точке i. Мы оказываемся на некоторой равнине и уже нашли r элементов на этой равнине.

Если i = n , то проход таблицы завершен. Мы внаем наилучшую возможную равнину с p повторениями и равнину с r элементами на последнем проходе, Мы берем лучшую из этих двух, и все кончено.

В противном случае нужно продвинуться вперед на один элемент. Либо этот элемент равен непосредственно предшествующему элементу; мы все еще находимся на той же самой равнине, длина которой увеличивается. Либо он отличается от предыдущего; тогда оказывается пройденной равнина длины r, которую при r > p нужно зарегистрировать как наилучшую. С другой стороны, нужно сказать, что новый элемент находится на равнине, которая в данный момент имеет длину 1.

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

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

Но это не все. Не позволяйте обмануть себя видимостью. Обе эти программы пробегают вектор элемент за элементом. Если вы составляете вашу программу на Бейсике или LSE, используя операторы ПЕРЕЙТИ К, а не циклы ДЛЯ или FOR, то вы убедитесь, что эти два решения почти неотличимы, а второе решение требует двукратного написания теста, сравнивающего r и p, так что едва ли не чаще эта вторая программа оказывается хуже.

Но есть третья стратегия. Восстановим общую ситуацию: мы прошли часть вектора до номера i включительно и определили наилучшую равнину длины p с общим значением ее элементов, равным x. Точка остановки произвольна.

Известно, что нужно осуществить включение нового элемента. Поставим следующий вопрос: насколько этот новый элемент может изменить ситуацию? Ответ: если он оказывается принадлежащим равнине с длиной, большей p. Может ли он оказаться принадлежащим равнине с длиной, намного большей p? Нет, мы бы это уже заметили. Следовательно, новый элемент изменяет ситуацию, если он принадлежит равнине длины p + 1. Но такое может случиться, если он равен элементу, содержащемуся в p предыдущих полях.

В начале ничего не пройдено: i = 0, и нет ни одного повторения: p = 0.

>i := 0; p := 0

>ВЫПОЛНЯТЬ

>  ЕСЛИ i = n ТО КОНЧЕНО

>  КОНЕЦ_ЕСЛИ

>  i := i + 1

>  ЕСЛИ a[i] = a[ip] ТО x := a[i]; p := p + 1

>  КОНЕЦ_ЕСЛИ

>ВЕРНУТЬСЯ

Красиво, не правда ли?

Но можно сделать лучше. Тщательно рассмотрите эту программу. Вы должны суметь обнаружить, что можно перескакивать через некоторое количество элементов без обращения к ним…

Головоломка 35.

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

Воспользуемся снова той же самой техникой. Пусть мы прошли вектор вплоть до некоторой точки. Пусть мы получили соответствующие результаты, но, поскольку мы еще не знаем, в какой форме они нужны, мы оставим их на некоторое время неопределенными. В любом случае выглядит вероятным, что мы знаем наибольшую по длине возрастающую подпоследовательность пройденной части, без которой мы как будто лишены возможности добраться до конца вектора… Как и выше, поставим вопрос: насколько изменяет ситуацию появление нового элемента? Он может продолжить известную нам наиболее длинную последовательность, если он может быть поставлен в ее конец, и, следовательно, если он больше последнего элемента этой последовательности. А если зто не так, то эту наиболее длинную подпоследовательность он изменить не может. Но он может продолжить более короткую подпоследовательность, которая постепенно может стать более длинной, если она медленнее растет.


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.