Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > Упрощение алгоритма |
Автор: sQu1rr 13.11.2009, 23:04 | ||||
В школе проходит олимпиада по информатике. У меня появилось пара вопросов Вот собственно задания https://docs.google.com/fileview?id=0B579cKBZiJ8tNjQ3NDVhYjUtMmUyMi00MTQ0LThmYzEtMDdhOTczYjljNzFl&hl=ru 3. У меня никак не получается сделать так, чтобы алгоритм перебора проходил за секнудну. Если он находит тройку диаметр которой 0, то программа завершается, а если нету такого, то идет полный перебор до конца... Не знаю, как с этим быть. Мое решение
6. Алгоритм сделал, но это тупой перебор всех ходов. Ну не может компьютер за нормальное кол-во времени выполнить поиск путей если комнат больше 10. Или я чтото неправильно делаю, или я не могу найти более простого пути. Сделал через рекурсию.
Не то что нуждаюсь в помощи, а просто ради интереса. Учитывая то что 5 заданий я сделал ( 3 походу и так сойдет ), я прошел первый тур олимпиады. И всетаки хочется увидеть более простые и интересные решения |
Автор: Abyx 14.11.2009, 00:11 |
3. надо использовать то, что числа упорядочены по неубыванию это значит, что если у тройки A[i] < B[j] <= C[k] диаметр равен D[i][j][k] то если A[i+1]<=B[j] то D[i+1][j][k]<=D[i][j][k] а если A[i+1]>B[j], то последовательности меняются местами, получается либо B[j] < A[i+1] <= C[k] либо B[j] <= C[k] <= A[i+1] при этом, диаметр либо уменьшается, либьо увеличивается. если уменьшается - следующий шаг, иначе сохраняем результат i,j,k как лучший найденный и ищем дальше Добавлено через 2 минуты и 6 секунд 6. классическая задача на графы. только перебор. читай гугл |
Автор: zkv 14.11.2009, 00:35 |
как бы неполный перебор. Принцип распространения волн Гюйгенеса может и должен (?) быть применен. Судя по коду рабочей функции (FindAllWays()) это сделано в точном соответствии с ним. |
Автор: sQu1rr 14.11.2009, 00:53 | ||||
Делал просто с логической точки зрения Код медленный изза постоянного применения разных функций, я его уже чутка подправил, стал получше ![]() А нету другого способа. Там значения до 10000 есть, а у меня 11 считает несколько минут на 4х ядерном core 2 (((((( Подравил:
И всетаки работает ужасно медленно. 11 комнат с 66 ходами "изучает" аж 4.5 минуты. Не представляю что будет с 100 комнатами. а с 1000? |
Автор: W4FhLF 14.11.2009, 09:17 | ||
А какая теоретическая сложность у алгоритма? Для оптимизации кода: 1. Откажись от использования vector<bool>. Очень медленный контейнер. Заюзая vector<unsigned char>. 2. vBool.push_back( (*ST).isPassed ); -- при вставке происходит постоянное перераспределение памяти. Тебе ведь заранее известен размер vBool, выделяй всю память при объявлении. 3.
А ты где-то используешь параллельные вычисления? Что-то я не вижу. |
Автор: Любитель 14.11.2009, 11:01 | ||||
От таких конструкций 100% лучше избавиться. Это же линейный проход по массиву! Учитывая, что твой оператор сравнения просто сравнивает номера - можно же просто обрашаться по индексу.
Это тоже не понял. Ты хочешь полностью сохранить состояние посещённых комнат, а потом вернуть? Ну.. в принципе лучше это делать инкрементно (благо в данном случае это очень просто), но явно не делая два полных (!) прохода по всем комнатам. А вообще - само собой лучше избавиться от рекурсии (используя очередь). |
Автор: sQu1rr 14.11.2009, 12:53 | ||||||||||
Не думаю, что это слишком поможет. Ну увеличится скорость на пару десятков процентов... и что? У меня 150 комнат считает больше 10 часов (((
Не подумал. Но это тоже не спасет производительность.
![]()
Попробую. исправить это
Так как vRooms содержит комнаты с указателями на комнаты, а копировать долго это все, то я просто сохраняю статус "пройденности" комнот перед рекурсией, потом восстанавливаю. Ато рекурсия работает пару раз, потом прекращается, так как все комнаты пройдены |
Автор: Любитель 14.11.2009, 12:58 | ||||||
На каждом шаге рекурсии ты заходишь в одну комнату. Её и помечаешь пройдённой. А в конце функции - убираешь этот флаг. Это я и называл инкрементным способом в данном случае (иначе - вычисление state[n+1] основано на state[n]). И, ещё раз - вообще рекурсия (с достаточно большим уровнем вложенности, в данном случае - до M) - это большой удар по производительности.
ИМХО, vector<bool> как раз быстрее.
Выигрыш без сомнения будет, но действительно не значителен. |
Автор: sQu1rr 14.11.2009, 13:03 | ||
Я чтото не догадался срасывать флаг вконце рекурсии То что рекурсия все портит, согласен, но я просто не представляю, как можно сделать по другому ((( ![]() ![]() ![]() Только что попробовал ваш "инкриментный способ". Время уменишилось почти в 250 раз. Тоесть вместо 4 минут задача решилась за 1 секунду. Попробую дальше, Спасибо огромное! |
Автор: Любитель 14.11.2009, 14:11 | ||
Любую рекурсию можно развернуть с использование стека или очереди. |
Автор: sQu1rr 14.11.2009, 14:20 |
Даже если я так сделаю, скорость вряд ли увеличится на много. Думаю, что нужен другой алгоритм решения. Не представляю какой ![]() |
Автор: Любитель 14.11.2009, 14:54 |
Проигрыш при использовании рекурсии достаточно значителен. Алгоритм - по-моему, тут особо больше ничего не придумаешь. |
Автор: sQu1rr 14.11.2009, 15:48 | ||
Я пока что сделал так - время уменьшилось на 40%. Ушел от STL, теперь все полностью на стандартных типах. Ща буду рекурсию переробатывать. Надеюсь получится. Если не сложно, опишите алгоритм именно для моей задачи. А то я чтото понять не могу ( *в размышлениях* ) |
Автор: Dov 14.11.2009, 18:14 | ||||
А так не пойдёт? Я особо не тестировал.
|
Автор: sQu1rr 14.11.2009, 19:12 |
Очень даже подойдет, правда я немного переработал, взял общий смысл Спасибо ) Мне бы решить 6ю задачу ![]() |
Автор: Любитель 15.11.2009, 00:17 | ||
Пропустил одну очень важную вещь - двойные вычисления. Добавь у комнаты поле, означающее количество путей из этой комнаты, в начале поставь, скажем -1. И напиши как-то так:
С генератором данных я не заморачивался - в качестве следующих допустимых комнат всегда ставил все ![]() |
Автор: sQu1rr 15.11.2009, 01:28 |
Не получится, ведь это просто запоминания всех возможных путей из комнаты. Ав разных ситациях пути разные и запомненный вариант выдает неправельный результат. У меня к примеру ошибка была аж на 9 000 000 ))) так что я подумаю над другим алгоритмом Если вам стало интересно - файл для проверки http://pastebin.com/m36dd4257 Правильный ответ: 9864101 http://pastebin.com/m2e4d7338 Правильный ответ: 18 Код моей программы: http://pastebin.com/m3d786e7d |
Автор: Любитель 16.11.2009, 01:19 |
Да, был не прав. Надо думать... ![]() Добавлено через 7 минут и 22 секунды Ээ.. Если во втором случае 18, то вы считаете что путь из A в B автоматически означает наличия пути из B в A. Вроде по условию это не так. Это не влияет на задачу, но влияет на парсинг входных данных. |
Автор: sQu1rr 16.11.2009, 02:03 | ||
Вы правы сейчас изменб алгоритм и посмотрю что получится. Какой я невнимательный. Спасибо зааранее! Кстати говоря, запоминание ходов сюда какраз походит ( то что вы написали что неправы ), так как здесь есть только ход вперед, не назад! |
Автор: sQu1rr 16.11.2009, 02:25 |
Спасибо за помощь - алгоритм правелен. Теперь на сервере, куда выкладываю задания появилось ( парвильный ответ - неправильный ответ ). Так что спасибо еще раз. Я скоро выложу еще некоторые проблемные места некоторых программ из этой же серии. У меня какаято ошибка в 3 задании ( решает один неправильно, один не укладывается в ограничение временное ), тоже саме в 4 задании. 5 я сделал полностью неправильно ![]() |
Автор: Любитель 16.11.2009, 13:48 | ||
Это самый быстрый, я думаю.
Всмысле? Мы перешли из 1 в 2, затем в 3 и посчитали, что из 3 будет 5 вариантов путей до конца. Допустим, что есть путь и из 2 в 3, и из 3 в 2 (это по условию возможно ведь?), тогда, если мы пойдём сразу из 1 в 3 можем получить другой ответ (для количества путей из 3). Добавлено через 2 минуты и 52 секунды Вообще условие мутное и не совсем согласуется с описанием входного формата. С двунаправленностью переходов тоже непонятно. Но, если ответы получаются правильные - значит видать решение правильное, но условие всё-таки сформулировано нечётко. |
Автор: sQu1rr 16.11.2009, 16:45 | ||
![]()
Ненавижу эстонию эстонцев и все что с ними связано. Моя мечта смыца отсюда ![]() У них всегда так |
Автор: sQu1rr 21.11.2009, 14:35 | ||
Слава богу, я почти со всем справился. Остался один алгоритм, который нужно упростить. Текст задания 4 на первой странице. Мой код
Ну не получается у меня решить задание за секунду... Не знаю как упростить, Сам алгоритм занимает 1/5 времени, а вод вывод почти 4/5. Прилагаю файл, который нужно посчитать за секунду. У меня тока за 1.7 выходит. А будут файлы побольше. Желательно сократить время до 0.5. Пологаю нужно както упростить функцию вывода cNodeList::GetPlace(); но алгоритм при 50000 строк вхдного файла всеравно почти 4 секунды считает Файл: http://pastebin.com/m5d524a54 |
Автор: MTWizard 22.11.2009, 14:32 |
Навеное таки 5-е задание, так? Вот решение, которое отрабатывает за 0,2 секунды: http://codepad.org/Jt7sEqFh |