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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Реализация алгоритма A*, В частности для игры 15 
:(
    Опции темы
Isaev
Дата 20.11.2010, 23:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



(Не получается откомпилировать пример из книги М.В. Мозговой - 85 нетривиальных проектов, решений и задач)
Проект на C++: <скачать>
Делаю в Dev-C++
Вылетает с единственной ошибкой в процессе компиляции
D:\Programme\Dev-Cpp\include\c++\3.4.2\bits\stl_function.h In member function `typename _Operation::result_type std::binder2nd<_Operation>::operator()(const typename _Operation::first_argument_type&) const [with _Operation = CompareVPtrs]':

187 D:\Programme\Dev-Cpp\include\c++\3.4.2\bits\stl_algo.h instantiated from `_InputIterator std::find_if(_InputIterator, _InputIterator, _Predicate, std::input_iterator_tag) [with _InputIterator = std::_Rb_tree_const_iterator<Vertex*>, _Predicate = std::binder2nd<CompareVPtrs>]'

336 D:\Programme\Dev-Cpp\include\c++\3.4.2\bits\stl_algo.h instantiated from `_InputIterator std::find_if(_InputIterator, _InputIterator, _Predicate) [with _InputIterator = std::_Rb_tree_const_iterator<Vertex*>, _Predicate = std::binder2nd<CompareVPtrs>]'

С чем это может быть связано?
PM MAIL ICQ   Вверх
Леопольд
Дата 21.11.2010, 12:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Isaev @  20.11.2010,  23:35 Найти цитируемый пост)
С чем это может быть связано?
С твоим кодом...



--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Isaev
Дата 21.11.2010, 13:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Леопольд @  21.11.2010,  12:32 Найти цитируемый пост)
С твоим кодом...

Вот не надо оффтопить на уважаемом форуме, если не чего сказать, лучше промолчи...
к тому же моего кода там пока нету
PM MAIL ICQ   Вверх
mes
Дата 21.11.2010, 14:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Код

#include <functional>
#include <algorithm>

это там есть?


--------------------
PM MAIL WWW   Вверх
Леопольд
Дата 21.11.2010, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Isaev @  21.11.2010,  13:47 Найти цитируемый пост)
Вот не надо оффтопить
А я не оффтоплю. Намекаю что bез пациента врач не может поставить диагноз.  smile
Выложи уже код, который
Цитата(Isaev @  20.11.2010,  23:35 Найти цитируемый пост)
Вылетает с единственной ошибкой в процессе компиляции


Или продолжим играть в угадайку?
Цитата(mes @  21.11.2010,  14:00 Найти цитируемый пост)
это там есть? 


Я как то реализовывал этот алгоритм, но код не из книги. На пятнашках тестировал. У меня всё компилируется... smile
http://forum.vingrad.ru/act-ST/f-92/t-3150.../p-2247690.html


Это сообщение отредактировал(а) Леопольд - 21.11.2010, 15:14


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
mes
Дата 21.11.2010, 14:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата(Леопольд @  21.11.2010,  13:10 Найти цитируемый пост)
Выложи уже код, который

Цитата(Isaev @  20.11.2010,  22:35 Найти цитируемый пост)
Проект на C++: <скачать>



Цитата(Леопольд @  21.11.2010,  13:10 Найти цитируемый пост)
Или продолжим играть в угадайку?
мне просто лень скачивать..
 учитывая вышенаписанное, автор не изменял в коде "из  книжки" ничего.. а значит скорей всего либо инклудов не хватает, либо компилятор не подходит.. так что в самом коде пока в принципе и смотреть нечего..
 smile 

Это сообщение отредактировал(а) mes - 21.11.2010, 14:16


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


Опытный
**


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

Репутация: 3
Всего: 13



Цитата(Isaev @  20.11.2010,  23:35 Найти цитируемый пост)
Проект на C++: <скачать>


Цитата(Леопольд @  21.11.2010,  14:10 Найти цитируемый пост)
Выложи уже код


Вроде он выложил  smile 


Цитата(Isaev @  21.11.2010,  13:47 Найти цитируемый пост)
Вот не надо оффтопить на уважаемом форуме, если не чего сказать, лучше промолчи...

Рейтинг: 0 Сообщений: 2 ...
Не надо наезжать на уважаемых програмистов уважаемого форума
PM MAIL Skype GTalk   Вверх
Леопольд
Дата 21.11.2010, 14:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(mes @  21.11.2010,  14:14 Найти цитируемый пост)
мне просто лень скачивать..
Черт, не заметил ссылки. Прошу прощения...

Добавлено @ 14:30
Isaev, код ужасный. Я-то сперва думал что мой понять сложнее ("наbросал" для сеbя)...
Сишные приведения типов, магические константы, одноbуквенные переменные и т.д. и т.п. Видимо автор никогда не писал "промышленный" код. Это хороший пример того, как не надо писать код.

P.S.
Терминология, используемая в моём коде, взята из книги "Artificial Intelligence: A Modern Approach 2nd edition"
P.P.S.
Никогда не нравились стандартные bиндеры. Ими очень легко "на###кодить"...

Это сообщение отредактировал(а) Леопольд - 21.11.2010, 14:47


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Леопольд
Дата 21.11.2010, 14:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(mes @  21.11.2010,  14:14 Найти цитируемый пост)
либо компилятор не подходит
Видимо, используется gcc. Я попроbовал g++ 4.5, текст ошиbок один в один.

Перепиши так:
Код
//функция для сравнения содержимого двух вершин, адресуемых указателями
struct CompareVPtrs:public binary_function<Vertex*,Vertex*,bool>
{
       bool operator()(Vertex *lhs, Vertex *rhs) const
       {
              //сравнить содержимое массивов lhs->State и rhs-State
              return equal((int *)lhs->State, (int *)lhs->State + 16,(int *)rhs->State);
       }
}
CompareVP;
и "включи" хидеры, которые указал mes.

Это сообщение отредактировал(а) Леопольд - 21.11.2010, 14:53


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Леопольд
Дата 21.11.2010, 15:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Код

  1 12  3  7
 15  2 14  4
  5  6 10  8
  9 13 11  0


Попроbовал решить "твоим" алгоритмом, через 5 минут надоело ждать (кильнул процесс)

Моя реализация (с теми же флагами компиляции: -O2) решает за ~10 сек.

Код

step 0
  1 12  3  7
 15  2 14  4
  5  6 10  8
  9 13 11   
step 1
  1 12  3  7
 15  2 14  4
  5  6 10  8
  9 13    11
step 2
  1 12  3  7
 15  2 14  4
  5  6     8
  9 13 10 11
step 3
  1 12  3  7
 15  2     4
  5  6 14  8
  9 13 10 11
step 4
  1 12  3  7
 15  2  4   
  5  6 14  8
  9 13 10 11
step 5
  1 12  3   
 15  2  4  7
  5  6 14  8
  9 13 10 11
step 6
  1 12     3
 15  2  4  7
  5  6 14  8
  9 13 10 11
step 7
  1    12  3
 15  2  4  7
  5  6 14  8
  9 13 10 11
step 8
  1  2 12  3
 15     4  7
  5  6 14  8
  9 13 10 11
step 9
  1  2 12  3
    15  4  7
  5  6 14  8
  9 13 10 11
step 10
  1  2 12  3
  5 15  4  7
     6 14  8
  9 13 10 11
step 11
  1  2 12  3
  5 15  4  7
  9  6 14  8
    13 10 11
step 12
  1  2 12  3
  5 15  4  7
  9  6 14  8
 13    10 11
step 13
  1  2 12  3
  5 15  4  7
  9  6 14  8
 13 10    11
step 14
  1  2 12  3
  5 15  4  7
  9  6     8
 13 10 14 11
step 15
  1  2 12  3
  5 15  4  7
  9  6  8   
 13 10 14 11
step 16
  1  2 12  3
  5 15  4   
  9  6  8  7
 13 10 14 11
step 17
  1  2 12  3
  5 15     4
  9  6  8  7
 13 10 14 11
step 18
  1  2     3
  5 15 12  4
  9  6  8  7
 13 10 14 11
step 19
  1  2  3   
  5 15 12  4
  9  6  8  7
 13 10 14 11
step 20
  1  2  3  4
  5 15 12   
  9  6  8  7
 13 10 14 11
step 21
  1  2  3  4
  5 15 12  7
  9  6  8   
 13 10 14 11
step 22
  1  2  3  4
  5 15 12  7
  9  6     8
 13 10 14 11
step 23
  1  2  3  4
  5 15     7
  9  6 12  8
 13 10 14 11
step 24
  1  2  3  4
  5    15  7
  9  6 12  8
 13 10 14 11
step 25
  1  2  3  4
  5  6 15  7
  9    12  8
 13 10 14 11
step 26
  1  2  3  4
  5  6 15  7
  9 10 12  8
 13    14 11
step 27
  1  2  3  4
  5  6 15  7
  9 10 12  8
 13 14    11
step 28
  1  2  3  4
  5  6 15  7
  9 10     8
 13 14 12 11
step 29
  1  2  3  4
  5  6     7
  9 10 15  8
 13 14 12 11
step 30
  1  2  3  4
  5  6  7   
  9 10 15  8
 13 14 12 11
step 31
  1  2  3  4
  5  6  7  8
  9 10 15   
 13 14 12 11
step 32
  1  2  3  4
  5  6  7  8
  9 10 15 11
 13 14 12   
step 33
  1  2  3  4
  5  6  7  8
  9 10 15 11
 13 14    12
step 34
  1  2  3  4
  5  6  7  8
  9 10    11
 13 14 15 12
step 35
  1  2  3  4
  5  6  7  8
  9 10 11   
 13 14 15 12
step 36
  1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14 15


P.S.
"Твой" код выдал решение через 500 сек.:
Код

  1 12  3  7
 15  2 14  4
  5  6 10  8
  9 13 11  0

1 2 3 4 
5 6 7 8 
9 10 11 12 
13 14 15 0 

1 2 3 4 
5 6 7 8 
9 10 11 0 
13 14 15 12 

1 2 3 4 
5 6 7 8 
9 10 0 11 
13 14 15 12 

1 2 3 4 
5 6 7 8 
9 10 15 11 
13 14 0 12 

1 2 3 4 
5 6 7 8 
9 10 15 11 
13 14 12 0 

1 2 3 4 
5 6 7 8 
9 10 15 0 
13 14 12 11 

1 2 3 4 
5 6 7 0 
9 10 15 8 
13 14 12 11 

1 2 3 0 
5 6 7 4 
9 10 15 8 
13 14 12 11 

1 2 0 3 
5 6 7 4 
9 10 15 8 
13 14 12 11 

1 2 7 3 
5 6 0 4 
9 10 15 8 
13 14 12 11 

1 2 7 3 
5 6 15 4 
9 10 0 8 
13 14 12 11 

1 2 7 3 
5 6 15 4 
9 10 12 8 
13 14 0 11 

1 2 7 3 
5 6 15 4 
9 10 12 8 
13 0 14 11 

1 2 7 3 
5 6 15 4 
9 0 12 8 
13 10 14 11 

1 2 7 3 
5 0 15 4 
9 6 12 8 
13 10 14 11 

1 2 7 3 
5 15 0 4 
9 6 12 8 
13 10 14 11 

1 2 7 3 
5 15 12 4 
9 6 0 8 
13 10 14 11 

1 2 7 3 
5 15 12 4 
9 6 8 0 
13 10 14 11 

1 2 7 3 
5 15 12 0 
9 6 8 4 
13 10 14 11 

1 2 7 0 
5 15 12 3 
9 6 8 4 
13 10 14 11 

1 2 0 7 
5 15 12 3 
9 6 8 4 
13 10 14 11 

1 2 12 7 
5 15 0 3 
9 6 8 4 
13 10 14 11 

1 2 12 7 
5 15 3 0 
9 6 8 4 
13 10 14 11 

1 2 12 7 
5 15 3 4 
9 6 8 0 
13 10 14 11 

1 2 12 7 
5 15 3 4 
9 6 0 8 
13 10 14 11 

1 2 12 7 
5 15 3 4 
9 6 14 8 
13 10 0 11 

1 2 12 7 
5 15 3 4 
9 6 14 8 
13 0 10 11 

1 2 12 7 
5 15 3 4 
9 6 14 8 
0 13 10 11 

1 2 12 7 
5 15 3 4 
0 6 14 8 
9 13 10 11 

1 2 12 7 
0 15 3 4 
5 6 14 8 
9 13 10 11 

1 2 12 7 
15 0 3 4 
5 6 14 8 
9 13 10 11 

1 0 12 7 
15 2 3 4 
5 6 14 8 
9 13 10 11 

1 12 0 7 
15 2 3 4 
5 6 14 8 
9 13 10 11 

1 12 3 7 
15 2 0 4 
5 6 14 8 
9 13 10 11 

1 12 3 7 
15 2 14 4 
5 6 0 8 
9 13 10 11 

1 12 3 7 
15 2 14 4 
5 6 10 8 
9 13 0 11 

1 12 3 7 
15 2 14 4 
5 6 10 8 
9 13 11 0 

42961вершин рассмотрено
Process returned 0 (0x0)   execution time : 504.968 s
Может здесь heuristic считает не через манхэтенское расстояние? Код читать уже сил нет...
Может стоит другого автора почитать?

Это сообщение отредактировал(а) Леопольд - 21.11.2010, 15:39


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Isaev
Дата 21.11.2010, 17:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(mes @  21.11.2010,  14:00 Найти цитируемый пост)
это там есть? 

это там было (добавлял), но убрал, т.к. не используется.

Цитата(Леопольд @  21.11.2010,  14:10 Найти цитируемый пост)
 Намекаю что bез пациента врач не может поставить диагноз.

ну так я ж сразу выложил в первом посте, сам не люблю когда надеются на экстрасенсовские способности smile

Цитата(mes @  21.11.2010,  14:14 Найти цитируемый пост)
а значит скорей всего либо инклудов не хватает, либо компилятор не подходит..

Да именно инклюдов то там и не было, но вроде я их все нагуглил...

Цитата(sQu1rr @  21.11.2010,  14:16 Найти цитируемый пост)
Рейтинг: 0 Сообщений: 2 ...
Не надо наезжать на уважаемых програмистов уважаемого форума 

Регистрация: 8.11.2007
Если я не участвую в обсуждениях, не значит, что не слежу за событиями ;)
форум грамотный и мне очень нравится... И это был не наезд, а он сам ссылку не заметил smile

Цитата(Леопольд @  21.11.2010,  14:17 Найти цитируемый пост)
код ужасный. Я-то сперва думал что мой понять сложнее ("наbросал" для сеbя)...
Сишные приведения типов, магические константы, одноbуквенные переменные и т.д. и т.п.

Это тоже не понравилось, т.к. по идее надо будет переводить в java а многое из этого кода даже не представляю как там сделать smile

Цитата(Леопольд @  21.11.2010,  14:17 Найти цитируемый пост)
Никогда не нравились стандартные bиндеры. Ими очень легко "на###кодить"...

Он у меня только потому стоит, что не требует переустановки, после сноса винды, а на си я обычно под линуксом кодю, а в виндовсе чаще на дельфи

Цитата(Леопольд @  21.11.2010,  14:49 Найти цитируемый пост)
Перепиши так:

да, да... именно в этой const дело было...
Цитата(Леопольд @  21.11.2010,  15:11 Найти цитируемый пост)
Может здесь heuristic считает не через манхэтенское расстояние?

Да нет, манхеттен там, вот строчка
Код

r+=abs(RowOf[State[i][j]]-i)+abs(ColOf[State[i][j]]-j);


Цитата(Леопольд @  21.11.2010,  15:11 Найти цитируемый пост)
Может стоит другого автора почитать?

Может стоит... Разница впечатляет, пойду твой код изучать, спасибо!

Это сообщение отредактировал(а) Isaev - 21.11.2010, 17:28
PM MAIL ICQ   Вверх
mes
Дата 21.11.2010, 17:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата(Isaev @  21.11.2010,  16:02 Найти цитируемый пост)
да, да... именно в этой const дело было...

тогда точно :
Цитата(Леопольд @  21.11.2010,  14:11 Найти цитируемый пост)
стоит другого автора почитать




--------------------
PM MAIL WWW   Вверх
Леопольд
Дата 21.11.2010, 19:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Isaev @  21.11.2010,  17:02 Найти цитируемый пост)
Может стоит... Разница впечатляет, пойду твой код изучать, спасибо!
Если переводит на джаву, то проще по смыслу.

Я использовал два контейнера с временем поиска ~log 2 n.
В одном "сидят" все разведанные состояния (discovered) с ценой от начала до этого состояния.
В другом "сидят" крайние (edge), из которых предполагается идти дальше. Сортируются по цене (heristic  до цели + цена от начала до этого состояния). Разные состояния могут иметь одинаковую цену, поэтому я использовал multiset.

Пихаем начальное состояние в edge и в discovered, и входим в цикл (крутится до тех пор, пока edge не пустой).

 В цикле, bерём первое из edge (с наименьшей ценой) и сравниваем с целью, если не совпадает, то "раскрываем" его (bestNode.expand() ). Проверяем все его производные, на предмет наличия в   discovered. Те, что там уже есть, отbрасываем, другие оцениваем (heristic  до цели и цена от начала до этого состояния, bestNode из discovered их parent). Выкидываем из edge bestNode и впихиваем в edge и в discovered его производные (которых не bыло в discovered).

Надо хранить ссылку на родителя (который в discovered), что-bы посчитать цену от начала до текущего состояния (я просто складывал цену от начала до родителя и heuristic от родителя до текущего). И для того, что-bы получить окончательное решение (цепочку состояний от начала до цели).

Здесь изложен смысл,но порядок действий можно сделать несколько иной.


Это сообщение отредактировал(а) Леопольд - 21.11.2010, 19:13


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Master01
Дата 21.11.2010, 21:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Я когда-то на этом собаку съел. Поэтому возьму на себя смелость дать пару советов smile

1. Списки open и close реально не нужны вообще. Гораздо "дешевле" просто сами узлы маркировать соотвественно, т.е. завести для каждого узла поля bool is_in_open и is_in_close. т.о. время определения есть ли узел в одном из "списков" = O(1), никаких логарифмов!

2. Для определения самого дешёвого узла используйте binary_heap на основе std::deque или std::vector это будет работать в разы быстрее чем любое дерево. (только тут придётся "умно" память оапределять под этот heap, чтобы избежать переаллокаций)

3. Вообще самая большая оптимизация - это правильно организовать само пространство поиска и чтение/запись в это пространство. 

Могу порекомендовать книги Game Programming Wisdom, там есть и про Astar и про представление пространств поиска (включая непрерывные игровые пространства!) и пр. Только вот самого  кода нету, конечно smile




PM MAIL   Вверх
Isaev
Дата 21.11.2010, 22:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Master01 а ты под 15 не реализовывал в своё время?
мне что-то подсказывает, что для поля 4х4 при современных то мощностях 10 сек это тоже много (при чём у меня это 18 сек, а не 10)
PM MAIL ICQ   Вверх
Леопольд
Дата 21.11.2010, 22:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Master01 @  21.11.2010,  21:23 Найти цитируемый пост)
Списки open и close реально не нужны вообще.
Есть только те, что уже известны, и те, которые, возможно, ведут к ещё неизвестным состояниям. У пятнашек пространство поиска 15! / 2 = 653 837 184 000 различных состояний (вторая половина недостижима из первой, и наоbорот). Достаточно много и для современных машин...

Цитата(Master01 @  21.11.2010,  21:23 Найти цитируемый пост)
время определения есть ли узел в одном из "списков" = O(1)
Это как? smile
В пятнашках, из одного состояния можно получить от двух, до четырёх других состояний. Как они могут bыть промаркированы beз использования списка уже открытых?
На дискретной карте (с количеством состояний менее чем M x N), для поиска пути, можно сделать O(1), не спорю. Если карта не слишком bольшая...

Цитата(Isaev @  21.11.2010,  22:15 Найти цитируемый пост)
(при чём у меня это 18 сек, а не 10) 
Запускал на решение код из "твоей" книги? Интересно за сколько у теbя решит...


Вот, по моему, самое узкое место:
Код
    static Node::HCost heurisicCost(Node const& from, Node const& to)
    {
        std::size_t cost = 0;
        for(std::size_t i = 0; i < FIELD; ++i)
        {
            if(from.m_state[i] != 0 && from.m_state[i] != to.m_state[i])
            {
                std::size_t fromCol = i % SIDE;
                std::size_t fromRow = i / SIDE;
                std::size_t index = getIndex(to.m_state,from.m_state[i]);
                std::size_t toCol = index % SIDE;
                std::size_t toRow = index / SIDE;

                cost += fromCol < toCol ? toCol - fromCol : fromCol - toCol;
                cost += fromRow < toRow ? toRow - fromRow : fromRow - toRow;
            }
        }
        return cost;
    }
я не заморачивался на производительности... Оптимизация может дать ощутимый  прирост.

Это сообщение отредактировал(а) Леопольд - 22.11.2010, 00:18


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
mes
Дата 22.11.2010, 00:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



из интереса: ИИ должен найти самое лучшее решение или любое, но быстро ?



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


Шустрый
*


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

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



Простите, я говорил, про A* приминительно к своей задаче, а касательно его применение к 15-шкам? я не очень силён... каким боком его тут прикрутить пока не представляю ...

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

На самом деле, A*-ра там было всего 10% от всей работы. Всё остальное было связано именно с представлением в памяти этого непрывного пространства. Непрывное оно было в том смысле что в нём было возможно перемещение в любом направлении, на любое предельно малое расстояние и любая координата могла быть взята с любой степенью точности (на практике, конечно, существовали ограничения, накладываемые самой ЭВМ).

Леопольд,

я не имел ввиду что не нужно вести учёт "открытых/закрытых". Я хотел сказать, что не нужны сами списки - как структура данных (ну или деревья и пр.) потому что поиск в них - минимум логарифм (тут уж лучше хэш таблицы, там сложность - таже константа). Правельнее делать отметки в самих узлах. Для этого, конечно, ваша карта должна хранить узлы в виде объектов. В свой класс node вы добавляете поле bool is_in_close и is_in_open. Далее обращение к этим полям, при условии что сам объект-узел у вас уже есть - тривальная операция.

Другой вопрос - какое время потребуется вашей карте, чтобы вернуть вам этот объект-узел? (на самом деле, тоже можно получить константу) Поэтому я и упомянул - "самая большая оптимизация - это правильно организовать само пространство поиска и чтение/запись в это пространство. "


mes,

Эвристика не гарантирует наилучшего решения, но зато работает быстро.

PM MAIL   Вверх
Леопольд
Дата 22.11.2010, 08:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Master01 @  22.11.2010,  00:26 Найти цитируемый пост)
 Для этого, конечно, ваша карта должна хранить узлы в виде объектов.
Это не карта...

Добавлено @ 08:26
Цитата(mes @  22.11.2010,  00:19 Найти цитируемый пост)
самое лучшее решение или любое, но быстро ?
Решение оптимальное. Тот же подход используется в методе ветвей и границ в задаче коммивояжёра. Эвристическая функция нужна, что-bы попытаться изbежать полного переbора.


Это сообщение отредактировал(а) Леопольд - 22.11.2010, 11:07


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Master01
Дата 22.11.2010, 12:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Леопольд @ 22.11.2010,  08:24)
Цитата(Master01 @  22.11.2010,  00:26 Найти цитируемый пост)
 Для этого, конечно, ваша карта должна хранить узлы в виде объектов.
Это не карта...

Не, я тут правильно сказал. 

Надо различать карту - как сущность, хранящую пространство, и сам Astar - механиз, осуществляющий в нём поиск. Их связывает лишь тонкий мостик - интерфейс, через, который Astar получает всю необходимую информацию о пространстве. А так, это две независимые сущности. К примеру, это значит, что вы можете менять методы представления пространства и при этом совершенно не нарушать работу самого Astar-а. (до тех пор, конечно, пока неизменным остаётся интерфейс)

Я привёл выше книги, в которых, это очень хорошо описано, включая архитектуру подобных систем и пр.
PM MAIL   Вверх
Леопольд
Дата 22.11.2010, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Isaev, я сейчас С++0x осваиваю, на нём код алгоритма понятнее:
Код
#ifndef ASTAR_SEARCH_HPP
#define ASTAR_SEARCH_HPP

#include <set>
#include <vector>
#include <algorithm>
#include <memory>

/////////////////////////////////////////////////
//! \brief A* algorithm implementation.
//!
//! \tparam
//! The Node type must correspond to STL container requirements.
//! and to the following interface:
//! "bool operator<(Node const&) const" to store in std::set (this critical part should be so fas as possible)
//! "bool operator ==(Node const&) const" to check equality of node state
//! "std::unique_ptr<std::vector<Node>> expand() const" to expand a node
//! "struct Node::HCost" with "bool operator<", "Node::HCost operator+", "Node::HCost & operator="
//! "static Node::HCost heurisicCost(Node const& from, Node const& to)"
//!
//! \param starting node
//! \param goal node
//! \return path from the starting node to the goal node
/////////////////////////////////////////////////
template<typename Node>
std::unique_ptr<std::vector<Node>> aStarSearch(Node const& start, Node const& goal)
{
    struct EstimatedNode
    {
        EstimatedNode(Node const& node, Node const& goal, EstimatedNode const* parent) :
            m_node(node), m_parent(parent),
            m_hRealCost(parent == NULL ? Node::heurisicCost(node, node) :
                parent->m_hRealCost + Node::heurisicCost(parent->m_node, node)),
            m_hGoalCost(m_hRealCost + Node::heurisicCost(node, goal))
        {}

        Node m_node;
        EstimatedNode const* m_parent;
        typename Node::HCost m_hRealCost;
        typename Node::HCost m_hGoalCost;

        //! \brief used in std::set
        bool operator< (EstimatedNode const& rsh) const {return this->m_node < rsh.m_node;}

        //! \brief used to compare with the goal Node
        bool operator== (Node const& rsh) const { return this->m_node == rsh; }
        //! \brief used to compare with the goal Node
        bool operator!= (Node const& rsh) const { return !(this->m_node == rsh); }
    };

    struct HCostLess{
        bool operator() (EstimatedNode const& lsh, EstimatedNode const& rsh) const {return lsh.m_hGoalCost < rsh.m_hGoalCost;}
    };

    typedef std::multiset<EstimatedNode, HCostLess>  EdgeT;

    std::set<EstimatedNode> discovered;
    EdgeT edge;

    auto bestNode = edge.insert(EstimatedNode(start, goal, NULL));

    std::unique_ptr<std::vector<Node>> result(new std::vector<Node>);
    while(!edge.empty())
    {
        if(*bestNode == goal)
        {
            EstimatedNode const* resNode = &(*bestNode);
            while(resNode != NULL)
            {
                result->push_back(resNode->m_node);
                resNode = resNode->m_parent;
            }
            std::reverse(result->begin(), result->end());
            return move(result);
        }

        std::unique_ptr<std::vector<Node>> expandedList(bestNode->m_node.expand());

        EstimatedNode const* parent = &(*discovered.insert(*bestNode).first);

        edge.erase(bestNode);

        for(auto it = expandedList->begin(); it != expandedList->end(); ++it)
        {
            EstimatedNode toEdge(*it, goal, parent);
            if(discovered.insert(toEdge).second)
            {
                edge.insert(toEdge);
            }
        }

        bestNode = edge.begin();
    }

    return move(result);
} // end of aStarSearch

#endif //ASTAR_SEARCH_HPP


Цитата(Master01 @  22.11.2010,  12:28 Найти цитируемый пост)
Не, я тут правильно сказал. 
Я имел ввиду что здесь речь про пятнашки, а не про карту.
Цитата(Master01 @  22.11.2010,  12:28 Найти цитируемый пост)
А так, это две независимые сущности
Если посмотришь код, то увидишь что сам алгоритм реализован отдельно.


Это сообщение отредактировал(а) Леопольд - 22.11.2010, 14:26


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Леопольд
Дата 22.11.2010, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Узкое место оказалось в Node::operator<
Так решает меньше чем за секунду...
Код
#include <cstring>
#include <iostream>
#include <iomanip>

#include "astar.hpp"

enum {SIDE = 4, FIELD = SIDE * SIDE};

std::size_t getIndex(std::size_t const (&state)[FIELD], std::size_t item)
{
    for(std::size_t i = 0; i < FIELD; ++i)
        if(state[i] == item) return i;
    return FIELD;
}

struct Node
{
    Node(std::size_t(&state)[FIELD]) {
        ::memcpy(this->m_state, state, FIELD * sizeof(std::size_t));
    }

    Node(std::initializer_list<std::size_t> initList) {
        std::copy(initList.begin(), initList.end(), this->m_state);
    }

    Node(Node const& rhs) {
        ::memcpy(this->m_state, rhs.m_state, FIELD * sizeof(std::size_t));
    }

    Node& operator= (Node const& rhs) {
        ::memcpy(this->m_state, rhs.m_state, FIELD * sizeof(std::size_t));
        return *this;
    }

    Node() {}

    std::size_t m_state[FIELD];

    bool operator< (Node const& rsh) const
    {
        return ::memcmp(this->m_state, rsh.m_state, FIELD * sizeof(std::size_t)) < 0;
    }

    bool operator== (Node const& rsh) const
    {
        return ::memcmp(this->m_state, rsh.m_state, FIELD * sizeof(std::size_t)) == 0;
    }

    std::unique_ptr<std::vector<Node>> expand() const
    {
        std::unique_ptr<std::vector<Node>> result(new std::vector<Node>);

        std::size_t index = getIndex(this->m_state, 0);

        std::size_t col = index % SIDE;
        std::size_t row = index / SIDE;

        if(0 < col) // move left
        {
            std::size_t copyState[FIELD];
            ::memcpy(copyState, this->m_state, FIELD * sizeof(std::size_t));
            std::swap(copyState[index-1], copyState[index]);
            result->push_back(Node(copyState));
        }
        if(col < SIDE-1) // move right
        {
            std::size_t copyState[FIELD];
            ::memcpy(copyState, this->m_state, FIELD * sizeof(std::size_t));
            std::swap(copyState[index], copyState[index+1]);
            result->push_back(Node(copyState));
        }
        if(0 < row) // move up
        {
            std::size_t copyState[FIELD];
            ::memcpy(copyState, this->m_state, FIELD * sizeof(std::size_t));
            std::swap(copyState[index-SIDE], copyState[index]);
            result->push_back(Node(copyState));
        }
        if(row < SIDE-1) // move down
        {
            std::size_t copyState[FIELD];
            ::memcpy(copyState, this->m_state, FIELD * sizeof(std::size_t));
            std::swap(copyState[index], copyState[index+SIDE]);
            result->push_back(Node(copyState));
        }
        return move(result);
    }

    typedef std::size_t HCost;

    static Node::HCost heurisicCost(Node const& from, Node const& to)
    {
        std::size_t cost = 0;

        for(int currentPos = 0; currentPos < FIELD; ++currentPos)
        {
            if(from.m_state[currentPos] != 0 && from.m_state[currentPos] != to.m_state[currentPos])
            {
                int goalPos = getIndex(to.m_state, from.m_state[currentPos]);
                cost += ::abs(goalPos - currentPos) / SIDE + ::abs(goalPos - currentPos) % SIDE;
            }
        }
        return cost;
    }

    void print() const
    {
        for(std::size_t i = 0; i < FIELD; ++i)
        {
            if(i % SIDE == 0) std::cout<<'\n';
            if(this->m_state[i] == 0)
            {
                std::cout<<"   ";
            }
            else
            {
                std::cout<<std::setw(3)<<this->m_state[i];
            }
        }
        std::cout<<"\n";
    }
};

std::size_t goal[FIELD] = {1, 2, 3, 4,
                           5, 6, 7, 8,
                           9, 10, 11, 12,
                           13, 14, 15, 0};

std::size_t start[FIELD] = {1, 12, 3, 7,
                            15, 2, 14, 4,
                            5, 6, 10, 8,
                            9, 13, 11, 0};

int main()
{
    auto result = aStarSearch(Node(start), Node(goal));

    std::size_t i = 0;
    for(auto it = result->begin(); it != result->end(); ++it)
    {
        std::cout<<"step "<<i++;
        it->print();
    }

    return 0;
}


Это сообщение отредактировал(а) Леопольд - 22.11.2010, 14:22


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Isaev
Дата 22.11.2010, 17:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Леопольд @  21.11.2010,  22:40 Найти цитируемый пост)
Запускал на решение код из "твоей" книги? Интересно за сколько у теbя решит...

из книги 450 сек, твой вариант из соседней темы 30 сек.

Цитата(Master01 @  22.11.2010,  00:26 Найти цитируемый пост)
Эвристика не гарантирует наилучшего решения, но зато работает быстро.

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

Цитата(Леопольд @  22.11.2010,  13:32 Найти цитируемый пост)
Узкое место оказалось в Node::operator<
Так решает меньше чем за секунду...

Да! я чувствовал smile
только собрать не могу, может что-то в инклюдах нету?
Код

Node(std::initializer_list<std::size_t> initList) {
        std::copy(initList.begin(), initList.end(), this->m_state);

19 D:\Programme\Dev-Cpp\Game15_Leo\main.cpp expected `)' before '<' token 
PM MAIL ICQ   Вверх
Леопольд
Дата 22.11.2010, 17:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Isaev, тут нужен С++0x (предполагаемый bудующий стандарт). Выкинь конструктор с std::initializer_list.
Измени мой код из соседней темы, он для текущего стандарта.


Это сообщение отредактировал(а) Леопольд - 22.11.2010, 17:41


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Isaev
Дата 22.11.2010, 18:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Леопольд,  а как отвязать этот код от boost
при трансляции на другой язык очень мешает
PM MAIL ICQ   Вверх
Master01
Дата 22.11.2010, 19:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Isaev @ 22.11.2010,  17:19)
Цитата(Master01 @  22.11.2010,  00:26 Найти цитируемый пост)
Эвристика не гарантирует наилучшего решения, но зато работает быстро.

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

Я рискну не поверить smile

Эвристические алгоритмы по своему определению не могут ничего гарантировать для общего случая, а Astar использует эвристику. Фактически это алгоритм Дейкстры (для которого, минимальность найденного пути гарантируется) с добавлением эвристики с целью сделать его быстрее.

Насчёт путей на карте, тоже, простите, не верно - [стоимость пути] != [длина пути]. Лучший путь (он же минимальный) не обязательно самый короткий, но стоимость его всегда минимальна. Под стоимостью тут понимайте что угодно - от банального расстояния, до денежной стоимости проезда по различным участкам.


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


Шустрый
*


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

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



Master01, из определения
  • A* (произносится «А со звездой») является лучшим из известных алгоритмов поиска пути. Он гарантирует поиск пути с наименьшим счетом, из всех возможных путей между двумя точками.
  • Хотя он и является лучшим алгоритмом поиска пути, A* также требует интенсивных вычислений процессора и работает медленно.
  • A* может обрабатывать многие виды поверхностей и находить лучший путь к цели через эти поверхности.

Цитата(Master01 @  22.11.2010,  19:29 Найти цитируемый пост)
 [стоимость пути] != [длина пути]. Лучший путь (он же минимальный) не обязательно самый короткий, но стоимость его всегда минимальна. Под стоимостью тут понимайте что угодно - от банального расстояния, до денежной стоимости проезда по различным участкам.

Мы об одним и том же, только с разных сторон smile
Именно если под стоимостью понимать банальное расстояние, то [стоимость пути] = [длина пути].
В общем это не столь важно...

Леопольд, я тоже помешан на оптимизации, это привито ещё спектрумом, где каждый байт был на счету...
У тебя был пример решения в 36 ходов, вот матрица для решения в 51 ход.
12, 2, 9, 13,
3, 11, 1, 10,
5, 14, 0, 4,
7, 15, 8, 6
оптимизированный вариант я пока так и не собрал, а старый её не тянет, т.к. после минут 5 вылетает по переполнению памяти. При чём странно работает, т.к. грузит процессор только вначале на полную, при этом используемая память быстро растёт до 860Мб потом быстро вниз до 50Мб и занятость процессора 10-20% так работает довольно долго, но потом вылетает... Странно.
У тебя он отработает? и за сколько?
PM MAIL ICQ   Вверх
Master01
Дата 22.11.2010, 21:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Isaev @ 22.11.2010,  20:20)
Master01, из определения

  • A* (произносится «А со звездой») является лучшим из известных алгоритмов поиска пути. Он гарантирует поиск пути с наименьшим счетом, из всех возможных путей между двумя точками.
  • Хотя он и является лучшим алгоритмом поиска пути, A* также требует интенсивных вычислений процессора и работает медленно.
  • A* может обрабатывать многие виды поверхностей и находить лучший путь к цели через эти поверхности.

Цитата(Master01 @  22.11.2010,  19:29 Найти цитируемый пост)
 [стоимость пути] != [длина пути]. Лучший путь (он же минимальный) не обязательно самый короткий, но стоимость его всегда минимальна. Под стоимостью тут понимайте что угодно - от банального расстояния, до денежной стоимости проезда по различным участкам.

Мы об одним и том же, только с разных сторон smile
Именно если под стоимостью понимать банальное расстояние, то [стоимость пути] = [длина пути].
В общем это не столь важно...

Isaev, я вам уже наверно надоел, да? smile

Все эти прекрасные свойства, описанные вами выше, выполняются только если ваша эвристическая функция h(x) всегда равна 0 (но тогда это уже алгоритм Дейкстры). Иными словами, если она гарантировано не привышает реально оставшегося расстояния до точки останова! т.е. когда мы можем ткнуть пальцем в небо и сказать, мол, до финиша не более N единиц стоимости. 
Если это возможно, то всё что вы написали выше - правда smile 

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

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

Цитата

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


http://ru.wikipedia.org/wiki/%D0%AD%D0%B2%...%B8%D1%82%D0%BC
PM MAIL   Вверх
Леопольд
Дата 22.11.2010, 21:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Isaev @  22.11.2010,  20:20 Найти цитируемый пост)
У тебя был пример решения в 36 ходов, вот матрица для решения в 51 ход.
12, 2, 9, 13,
3, 11, 1, 10,
5, 14, 0, 4,
7, 15, 8, 6
Видимо нерешаемый, мой на нём тоже зависает наглухо, памяти не хватает. А если решаемый, то очевидно памяти надо bольше. 

Код
 12 13 15  7
  5  3  4  8
  9 14  1  0
 10  2  6 11

Для решения в 51 ход пришлось оптимизировать по памяти. Отъедало всю доступную (1.6 GB), потом , видимо, начинала юзать swap, и нагрузка на процессор падала до 1-5%. Теперь юзает ~400 MB .
Код
#include <cstring>
#include <iostream>
#include <iomanip>

#include "astar.hpp"

enum {SIDE = 4, FIELD = SIDE * SIDE};

typedef unsigned char Item;

std::size_t getIndex(Item const (&state)[FIELD], Item item)
{
    for(std::size_t i = 0; i < FIELD; ++i)
        if(state[i] == item) return i;
    return FIELD;
}

struct Node
{
    Node(Item (&state) [FIELD]) {
        ::memcpy(this->m_state, state, FIELD * sizeof(Item));
    }

    Node(Node const& rhs) {
        ::memcpy(this->m_state, rhs.m_state, FIELD * sizeof(Item));
    }

    Node& operator= (Node const& rhs) {
        ::memcpy(this->m_state, rhs.m_state, FIELD * sizeof(Item));
        return *this;
    }

    Node() {}

    Item m_state[FIELD];

    bool operator< (Node const& rsh) const
    {
        return ::memcmp(this->m_state, rsh.m_state, FIELD * sizeof(Item)) < 0;
    }

    bool operator== (Node const& rsh) const
    {
        return ::memcmp(this->m_state, rsh.m_state, FIELD * sizeof(Item)) == 0;
    }

    std::unique_ptr<std::vector<Node>> expand() const
    {
        std::unique_ptr<std::vector<Node>> result(new std::vector<Node>);

        std::size_t index = getIndex(this->m_state, 0);

        std::size_t col = index % SIDE;
        std::size_t row = index / SIDE;

        if(0 < col) // move left
        {
            Item copyState[FIELD];
            ::memcpy(copyState, this->m_state, FIELD * sizeof(Item));
            std::swap(copyState[index-1], copyState[index]);
            result->push_back(Node(copyState));
        }
        if(col < SIDE-1) // move right
        {
            Item copyState[FIELD];
            ::memcpy(copyState, this->m_state, FIELD * sizeof(Item));
            std::swap(copyState[index], copyState[index+1]);
            result->push_back(Node(copyState));
        }
        if(0 < row) // move up
        {
            Item copyState[FIELD];
            ::memcpy(copyState, this->m_state, FIELD * sizeof(Item));
            std::swap(copyState[index-SIDE], copyState[index]);
            result->push_back(Node(copyState));
        }
        if(row < SIDE-1) // move down
        {
            Item copyState[FIELD];
            ::memcpy(copyState, this->m_state, FIELD * sizeof(Item));
            std::swap(copyState[index], copyState[index+SIDE]);
            result->push_back(Node(copyState));
        }
        return move(result);
    }

    typedef std::size_t HCost;

    static Node::HCost heurisicCost(Node const& from, Node const& to)
    {
        std::size_t cost = 0;

        for(int currentPos = 0; currentPos < FIELD; ++currentPos)
        {
            if(from.m_state[currentPos] != 0 && from.m_state[currentPos] != to.m_state[currentPos])
            {
                int goalPos = getIndex(to.m_state, from.m_state[currentPos]);
                cost += ::abs(goalPos - currentPos) / SIDE + ::abs(goalPos - currentPos) % SIDE;
            }
        }
        return cost;
    }

    void print() const
    {
        for(std::size_t i = 0; i < FIELD; ++i)
        {
            if(i % SIDE == 0) std::cout<<'\n';
            if(this->m_state[i] == 0)
            {
                std::cout<<"   ";
            }
            else
            {
                std::cout<<std::setw(3)<<static_cast<std::size_t>(this->m_state[i]);
            }
        }
        std::cout<<"\n";
    }
};

Item goal[FIELD] = {1, 2, 3, 4,
                    5, 6, 7, 8,
                    9, 10, 11, 12,
                    13, 14, 15, 0};

Item start[FIELD] = {12, 13, 15, 7,
                    5, 3, 4, 8,
                    9, 14, 1, 0,
                    10, 2, 6, 11};

//Item start[FIELD] = {12, 2, 9, 13,
//                    3, 11, 1, 10,
//                    5, 14, 0, 4,
//                    7, 15, 8, 6};

int main()
{
    auto result = aStarSearch(Node(start), Node(goal));

    std::size_t i = 0;
    for(auto it = result->begin(); it != result->end(); ++it)
    {
        std::cout<<"step "<<i++;
        it->print();
    }

    return 0;
}


execution time : 16.759 s (AMD Athlon X2 4000+, Ubuntu 10.10, g++4.5)
Код
step 0
 12 13 15  7
  5  3  4  8
  9 14  1   
 10  2  6 11
step 1
 12 13 15  7
  5  3  4   
  9 14  1  8
 10  2  6 11
step 2
 12 13 15  7
  5  3     4
  9 14  1  8
 10  2  6 11
step 3
 12 13     7
  5  3 15  4
  9 14  1  8
 10  2  6 11
step 4
 12    13  7
  5  3 15  4
  9 14  1  8
 10  2  6 11
step 5
 12  3 13  7
  5    15  4
  9 14  1  8
 10  2  6 11
step 6
 12  3 13  7
  5 14 15  4
  9     1  8
 10  2  6 11
step 7
 12  3 13  7
  5 14 15  4
  9  1     8
 10  2  6 11
step 8
 12  3 13  7
  5 14     4
  9  1 15  8
 10  2  6 11
step 9
 12  3     7
  5 14 13  4
  9  1 15  8
 10  2  6 11
step 10
 12     3  7
  5 14 13  4
  9  1 15  8
 10  2  6 11
step 11
    12  3  7
  5 14 13  4
  9  1 15  8
 10  2  6 11
step 12
  5 12  3  7
    14 13  4
  9  1 15  8
 10  2  6 11
step 13
  5 12  3  7
 14    13  4
  9  1 15  8
 10  2  6 11
step 14
  5     3  7
 14 12 13  4
  9  1 15  8
 10  2  6 11
step 15
  5  3     7
 14 12 13  4
  9  1 15  8
 10  2  6 11
step 16
  5  3  7   
 14 12 13  4
  9  1 15  8
 10  2  6 11
step 17
  5  3  7  4
 14 12 13   
  9  1 15  8
 10  2  6 11
step 18
  5  3  7  4
 14 12 13  8
  9  1 15   
 10  2  6 11
step 19
  5  3  7  4
 14 12 13  8
  9  1    15
 10  2  6 11
step 20
  5  3  7  4
 14 12     8
  9  1 13 15
 10  2  6 11
step 21
  5  3  7  4
 14    12  8
  9  1 13 15
 10  2  6 11
step 22
  5  3  7  4
 14  1 12  8
  9    13 15
 10  2  6 11
step 23
  5  3  7  4
 14  1 12  8
  9  2 13 15
 10     6 11
step 24
  5  3  7  4
 14  1 12  8
  9  2 13 15
 10  6    11
step 25
  5  3  7  4
 14  1 12  8
  9  2    15
 10  6 13 11
step 26
  5  3  7  4
 14  1     8
  9  2 12 15
 10  6 13 11
step 27
  5  3     4
 14  1  7  8
  9  2 12 15
 10  6 13 11
step 28
  5     3  4
 14  1  7  8
  9  2 12 15
 10  6 13 11
step 29
  5  1  3  4
 14     7  8
  9  2 12 15
 10  6 13 11
step 30
  5  1  3  4
 14  2  7  8
  9    12 15
 10  6 13 11
step 31
  5  1  3  4
 14  2  7  8
  9  6 12 15
 10    13 11
step 32
  5  1  3  4
 14  2  7  8
  9  6 12 15
    10 13 11
step 33
  5  1  3  4
 14  2  7  8
     6 12 15
  9 10 13 11
step 34
  5  1  3  4
     2  7  8
 14  6 12 15
  9 10 13 11
step 35
     1  3  4
  5  2  7  8
 14  6 12 15
  9 10 13 11
step 36
  1     3  4
  5  2  7  8
 14  6 12 15
  9 10 13 11
step 37
  1  2  3  4
  5     7  8
 14  6 12 15
  9 10 13 11
step 38
  1  2  3  4
  5  6  7  8
 14    12 15
  9 10 13 11
step 39
  1  2  3  4
  5  6  7  8
 14 10 12 15
  9    13 11
step 40
  1  2  3  4
  5  6  7  8
 14 10 12 15
  9 13    11
step 41
  1  2  3  4
  5  6  7  8
 14 10 12 15
  9 13 11   
step 42
  1  2  3  4
  5  6  7  8
 14 10 12   
  9 13 11 15
step 43
  1  2  3  4
  5  6  7  8
 14 10    12
  9 13 11 15
step 44
  1  2  3  4
  5  6  7  8
 14    10 12
  9 13 11 15
step 45
  1  2  3  4
  5  6  7  8
    14 10 12
  9 13 11 15
step 46
  1  2  3  4
  5  6  7  8
  9 14 10 12
    13 11 15
step 47
  1  2  3  4
  5  6  7  8
  9 14 10 12
 13    11 15
step 48
  1  2  3  4
  5  6  7  8
  9    10 12
 13 14 11 15
step 49
  1  2  3  4
  5  6  7  8
  9 10    12
 13 14 11 15
step 50
  1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14    15
step 51
  1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14 15   

Process returned 0 (0x0)   execution time : 16.759 s
Press ENTER to continue.


решение в 52 хода съело ~1GB...

Это сообщение отредактировал(а) Леопольд - 23.11.2010, 08:17


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Леопольд
Дата 22.11.2010, 23:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Isaev @  22.11.2010,  18:11 Найти цитируемый пост)
Леопольд,  а как отвязать этот код от boost
при трансляции на другой язык очень мешает 
В джаве есть сbорщик мусора, так что на всевозможные _ptr просто "заbить", это очистка памяти. Foreach, вроде, тоже есть в джаве...

Не уверен что стоит делать на джаве, она ведь гораздо дольше раbотает... Разве нельзя какой-ниbуть bиндер к С++ или С использовать?
Код
extern "C" void binderC()
{
    auto result = aStarSearch(Node(start), Node(goal));
    //transfer the result to the java code
}



Это сообщение отредактировал(а) Леопольд - 22.11.2010, 23:40


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Isaev
Дата 23.11.2010, 06:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Master01 @  22.11.2010,  21:24 Найти цитируемый пост)
Isaev, я вам уже наверно надоел, да?

Нет конечно, просто счёт был на часы и не хотелось спорить о теории... Т.к. не полностью в неё вник, к сожалению, чтобы спорить надо было разбираться smile
получается эвристика может быть любая, не обязательно по манхеттену, и пришла потому мысль, что алго из книги тупил именно по этому, там же в расчёче эвристики забиты 2 массива жёстко для какого-то примера, а ввод поля с клавиатуры, как то это тупо... Может потому для другого поля получался далеко не манхеттен, но к решению он преходил, только какой ценой?
Надо будет поиграться проверить smile

Цитата(Леопольд @  22.11.2010,  21:40 Найти цитируемый пост)
 Теперь юзает ~400 MB .
execution time : 16.759 s (AMD Athlon X2 4000+, Ubuntu 10.10, g++4.5)

smile Талант! Как время будет, надо будет в пару алго подумать над оптимизацией... Может снова пристану.
C++0x в какой среде компилируется? Я о таком не слышал даже пока, думал 0x случайный мусор. Надо будет всё таки собрать последний пример.

Цитата(Леопольд @  22.11.2010,  23:32 Найти цитируемый пост)
Не уверен что стоит делать на джаве, она ведь гораздо дольше раbотает...

Это ясно... Это у сестры лабораторная была, на яве, потому никуда не денешься, но идея затянула smile
лабу сдали, на 51 ход вглубину ява тоже повесилась (куча переполнилась), а остальное нормально считала, но чуть дольше... 
Для себя переведу позже на Delphi, приятный пример.
Как оценить для поля 4х4 максимально длинной решение? 51 это же не предел?

PM MAIL ICQ   Вверх
Леопольд
Дата 23.11.2010, 08:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Isaev @  23.11.2010,  06:06 Найти цитируемый пост)
Как оценить для поля 4х4 максимально длинной решение? 51 это же не предел?
Не знаю. Знаю только что для 3х3 макс. 24 хода. Как считать, не разbирался. Меня сам A* интересовал.

Цитата(Isaev @  23.11.2010,  06:06 Найти цитируемый пост)
C++0x в какой среде компилируется?
g++ 4.5, VS 2010

Цитата(Isaev @  23.11.2010,  06:06 Найти цитируемый пост)
думал 0x случайный мусор
Это пока ещё драфт. Стандарт не принят (хотели вроде в 2007 принять, поначалу), так что всё может поменяться.

Цитата(Isaev @  23.11.2010,  06:06 Найти цитируемый пост)
получается эвристика может быть любая, не обязательно по манхеттену
можно ещё оценивать по количеству костяшек, находящихся не на своём месте. Но ресурсов для решения потреbуется в разы bольше.


Это сообщение отредактировал(а) Леопольд - 23.11.2010, 08:12


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Master01
Дата 23.11.2010, 16:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Эвристическая функция это Ахилесова пята Astar-а.

Если она переоценивает оставшееся расстояние, то алгоритм может вернуть не самый минимальный путь. НО с другой стороны, если недооценивает, то алгоритм теряет направленность, т.е. начинает рыскать как алгоритм Дейкстры, работает медленее.

На самом деле, в задаче поиска реальных путей на карте для эвристики используется тот же манхэтен, хотя это по сути не правильно, поскольку dx + dy (манхэттэн-расстояние) всега заведомо больше sqrt(dx^2 + dy^2) (при положительных dx и dy). т.е. такая эвристика всегда 100% нарушает условие допустимости эвристической функции. 
Это приводит к тому, что найденные пути могут быть не самыми минимальными. Но зато dx + dy высчитывается несравнимо быстрее чем квадрадный корень из суммы квадратов. 

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

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


Шустрый
*


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

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



Цитата(Master01 @  23.11.2010,  16:21 Найти цитируемый пост)
На самом деле, в задаче поиска реальных путей на карте для эвристики используется тот же манхэтен, хотя это по сути не правильно, поскольку dx + dy (манхэттэн-расстояние) всега заведомо больше sqrt(dx^2 + dy^2) (при положительных dx и dy). т.е. такая эвристика всегда 100% нарушает условие допустимости эвристической функции. 

ну применимо к картам никто не мешает изменить эвристическую оценку к тому же sqrt(dx^2 + dy^2), если такой путь часто имеет место быть, то оно себя окупит... а вычисления всегда можно оптимизировать разложив до булевых операций и сдвигов, и скорость будет вполне сносной...

Возвращаясь к теме (в частности к 4х4):
если я обрабатываю числа не по порядку, а допустим сначала так
+----+----+----+----+
|  1  |  2  |  3  |  4  |
+----+----+----+----+
|  5  |      |      |      |
+----+----+----+----+
|  9  |      |      |      |
+----+----+----+----+
| 13 |      |      |      |
+----+----+----+----+
а потом 3х3 это же выведет алгоритм раньше к правильному решению? Или я не совсем допонимаю принцып?
PM MAIL ICQ   Вверх
Леопольд
Дата 23.11.2010, 20:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Код
Item goal[FIELD] = {1, 2, 3, 4,
                    5, 6, 7, 8,
                    9, 10, 11, 12,
                    13, 14, 15, 0};

Item start[FIELD] = {15, 12, 14, 7,
                    5, 3, 6, 4,
                    9, 10, 2, 0,
                    13, 1, 11, 8};

//Item start[FIELD] = {15, 12, 14, 7,
//                    5, 3, 6, 2,
//                    9, 10, 11, 8,
//                    13, 1, 4, 0};


int main()
{
    auto result = aStarSearchBidirect(Node(start), Node(goal));
    std::size_t i = 0;
    for(auto it = result->begin(); it != result->end(); ++it)
    {
        std::cout<<"step "<<i++;
        it->print();
    }

    return 0;
}


step 51 execution time : 0.383 s
Код
step 0
 12 13 15  7
  5  3  4  8
  9 14  1   
 10  2  6 11
step 1
 12 13 15  7
  5  3  4   
  9 14  1  8
 10  2  6 11
step 2
 12 13 15  7
  5  3     4
  9 14  1  8
 10  2  6 11
step 3
 12 13     7
  5  3 15  4
  9 14  1  8
 10  2  6 11
step 4
 12    13  7
  5  3 15  4
  9 14  1  8
 10  2  6 11
step 5
    12 13  7
  5  3 15  4
  9 14  1  8
 10  2  6 11
step 6
  5 12 13  7
     3 15  4
  9 14  1  8
 10  2  6 11
step 7
  5 12 13  7
  9  3 15  4
    14  1  8
 10  2  6 11
step 8
  5 12 13  7
  9  3 15  4
 14     1  8
 10  2  6 11
step 9
  5 12 13  7
  9  3 15  4
 14  1     8
 10  2  6 11
step 10
  5 12 13  7
  9  3     4
 14  1 15  8
 10  2  6 11
step 11
  5 12     7
  9  3 13  4
 14  1 15  8
 10  2  6 11
step 12
  5    12  7
  9  3 13  4
 14  1 15  8
 10  2  6 11
step 13
  5  3 12  7
  9    13  4
 14  1 15  8
 10  2  6 11
step 14
  5  3 12  7
  9  1 13  4
 14    15  8
 10  2  6 11
step 15
  5  3 12  7
  9  1 13  4
    14 15  8
 10  2  6 11
step 16
  5  3 12  7
     1 13  4
  9 14 15  8
 10  2  6 11
step 17
  5  3 12  7
  1    13  4
  9 14 15  8
 10  2  6 11
step 18
  5  3 12  7
  1 13     4
  9 14 15  8
 10  2  6 11
step 19
  5  3     7
  1 13 12  4
  9 14 15  8
 10  2  6 11
step 20
  5  3  7   
  1 13 12  4
  9 14 15  8
 10  2  6 11
step 21
  5  3  7  4
  1 13 12   
  9 14 15  8
 10  2  6 11
step 22
  5  3  7  4
  1 13 12  8
  9 14 15   
 10  2  6 11
step 23
  5  3  7  4
  1 13 12  8
  9 14    15
 10  2  6 11
step 24
  5  3  7  4
  1 13 12  8
  9    14 15
 10  2  6 11
step 25
  5  3  7  4
  1    12  8
  9 13 14 15
 10  2  6 11
step 26
  5  3  7  4
     1 12  8
  9 13 14 15
 10  2  6 11
step 27
  5  3  7  4
  9  1 12  8
    13 14 15
 10  2  6 11
step 28
  5  3  7  4
  9  1 12  8
 13    14 15
 10  2  6 11
step 29
  5  3  7  4
  9  1 12  8
 13  2 14 15
 10     6 11
step 30
  5  3  7  4
  9  1 12  8
 13  2 14 15
 10  6    11
step 31
  5  3  7  4
  9  1 12  8
 13  2    15
 10  6 14 11
step 32
  5  3  7  4
  9  1     8
 13  2 12 15
 10  6 14 11
step 33
  5  3     4
  9  1  7  8
 13  2 12 15
 10  6 14 11
step 34
  5     3  4
  9  1  7  8
 13  2 12 15
 10  6 14 11
step 35
  5  1  3  4
  9     7  8
 13  2 12 15
 10  6 14 11
step 36
  5  1  3  4
  9  2  7  8
 13    12 15
 10  6 14 11
step 37
  5  1  3  4
  9  2  7  8
 13  6 12 15
 10    14 11
step 38
  5  1  3  4
  9  2  7  8
 13  6 12 15
    10 14 11
step 39
  5  1  3  4
  9  2  7  8
     6 12 15
 13 10 14 11
step 40
  5  1  3  4
     2  7  8
  9  6 12 15
 13 10 14 11
step 41
     1  3  4
  5  2  7  8
  9  6 12 15
 13 10 14 11
step 42
  1     3  4
  5  2  7  8
  9  6 12 15
 13 10 14 11
step 43
  1  2  3  4
  5     7  8
  9  6 12 15
 13 10 14 11
step 44
  1  2  3  4
  5  6  7  8
  9    12 15
 13 10 14 11
step 45
  1  2  3  4
  5  6  7  8
  9 10 12 15
 13    14 11
step 46
  1  2  3  4
  5  6  7  8
  9 10 12 15
 13 14    11
step 47
  1  2  3  4
  5  6  7  8
  9 10 12 15
 13 14 11   
step 48
  1  2  3  4
  5  6  7  8
  9 10 12   
 13 14 11 15
step 49
  1  2  3  4
  5  6  7  8
  9 10    12
 13 14 11 15
step 50
  1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14    15
step 51
  1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14 15   

Process returned 0 (0x0)   execution time : 0.383 s


Код
#ifndef ASTAR_B_HPP_INCLUDED
#define ASTAR_B_HPP_INCLUDED

#include <set>
#include <vector>
#include <algorithm>
#include <memory>

/////////////////////////////////////////////////
//! \brief A* algorithm implementation.
//!
//! \tparam
//! The Node type must correspond to STL container requirements.
//! and to the following interface:
//! "bool operator<(Node const&) const" to store in std::set (this critical part should be so fas as possible)
//! "bool operator ==(Node const&) const" to check equality of node state
//! "std::unique_ptr<std::vector<Node>> expand() const" to expand a node
//! "struct Node::HCost" with "bool operator<", "Node::HCost operator+", "Node::HCost & operator="
//! "static Node::HCost heurisicCost(Node const& from, Node const& to)"
//!
//! \param starting node
//! \param goal node
//! \return path from the starting node to the goal node
/////////////////////////////////////////////////
template<typename Node>
std::unique_ptr<std::vector<Node>> aStarSearchBidirect(Node const& start, Node const& goal)
{
    struct EstimatedNode
    {
        EstimatedNode(Node const& node, Node const& goal, EstimatedNode const* parent) :
            m_node(node), m_parent(parent),
            m_hRealCost(parent == NULL ? Node::heurisicCost(node, node) :
                parent->m_hRealCost + Node::heurisicCost(parent->m_node, node)),
            m_hGoalCost(m_hRealCost + Node::heurisicCost(node, goal))
        {}

        Node m_node;
        EstimatedNode const* m_parent;
        typename Node::HCost m_hRealCost;
        typename Node::HCost m_hGoalCost;

        //! \brief used in std::set
        bool operator< (EstimatedNode const& rsh) const {return this->m_node < rsh.m_node;}

        //! \brief used to compare with the goal Node
        bool operator== (Node const& rsh) const { return this->m_node == rsh; }
        //! \brief used to compare with the goal Node
        bool operator!= (Node const& rsh) const { return !(this->m_node == rsh); }
    };

    struct HCostLess{
        bool operator() (EstimatedNode const* lsh, EstimatedNode const* rsh) const {return lsh->m_hGoalCost < rsh->m_hGoalCost;}
    };

    typedef std::multiset<EstimatedNode const*, HCostLess>  EdgeT;

    std::set<EstimatedNode> discoveredF({EstimatedNode(start, goal, NULL)});
    std::set<EstimatedNode> discoveredB({EstimatedNode(goal, start, NULL)});

    EstimatedNode const* bestNodeF = &(*discoveredF.begin());
    EstimatedNode const* bestNodeB = &(*discoveredB.begin());

    EdgeT edgeF({bestNodeF});
    EdgeT edgeB({bestNodeB});


    std::unique_ptr<std::vector<Node>> path(new std::vector<Node>);

    while(edgeF.empty() == false && edgeB.empty() == false)
    {

        auto match = discoveredB.find(*bestNodeF);
        if(match != discoveredB.end())
        {
            // the solution is found
            EstimatedNode const* point = bestNodeF;
            for(; point != NULL; point = point->m_parent)
            {
                path->push_back(point->m_node);
            }
            std::reverse(path->begin(), path->end());

            point = match->m_parent;
            for(; point != NULL; point = point->m_parent)
            {
                path->push_back(point->m_node);
            }

            return move(path);
        }

        edgeF.erase(edgeF.begin());

        auto expandedListF = bestNodeF->m_node.expand();

        for(auto it = expandedListF->begin(); it != expandedListF->end(); ++it)
        {
            auto result = discoveredF.insert(EstimatedNode(*it, goal, bestNodeF));
            if(result.second)
            {
                EstimatedNode const* newNode = &(*result.first);
                edgeF.insert(newNode);
            }
        }
        bestNodeF = *edgeF.begin();

        match = discoveredF.find(*bestNodeB);
        if(match != discoveredF.end())
        {
            EstimatedNode const* point = match->m_parent;
            for(; point != NULL; point = point->m_parent)
            {
                path->push_back(point->m_node);
            }
            std::reverse(path->begin(), path->end());

            point = bestNodeB;
            for(; point != NULL; point = point->m_parent)
            {
                path->push_back(point->m_node);
            }

            return move(path);
        }

        edgeB.erase(edgeB.begin());

        auto expandedListB = bestNodeB->m_node.expand();

        for(auto it = expandedListB->begin(); it != expandedListB->end(); ++it)
        {
            auto result = discoveredB.insert(EstimatedNode(*it, start, bestNodeB));
            if(result.second)
            {
                EstimatedNode const* newNode = &(*result.first);

                edgeB.insert(newNode);
            }
        }
        bestNodeB = *edgeB.begin();
    }

    return move(path);
}

#endif // ASTAR_B_HPP_INCLUDED


Добавлено @ 20:52
step 60  execution time : 5.352 s
Код
step 0
 15 12 14  7
  5  3  6  2
  9 10 11  8
 13  1  4   
step 1
 15 12 14  7
  5  3  6  2
  9 10 11  8
 13  1     4
step 2
 15 12 14  7
  5  3  6  2
  9 10     8
 13  1 11  4
step 3
 15 12 14  7
  5  3  6  2
  9    10  8
 13  1 11  4
step 4
 15 12 14  7
  5  3  6  2
  9  1 10  8
 13    11  4
step 5
 15 12 14  7
  5  3  6  2
  9  1 10  8
 13 11     4
step 6
 15 12 14  7
  5  3  6  2
  9  1     8
 13 11 10  4
step 7
 15 12 14  7
  5  3     2
  9  1  6  8
 13 11 10  4
step 8
 15 12     7
  5  3 14  2
  9  1  6  8
 13 11 10  4
step 9
 15    12  7
  5  3 14  2
  9  1  6  8
 13 11 10  4
step 10
    15 12  7
  5  3 14  2
  9  1  6  8
 13 11 10  4
step 11
  5 15 12  7
     3 14  2
  9  1  6  8
 13 11 10  4
step 12
  5 15 12  7
  3    14  2
  9  1  6  8
 13 11 10  4
step 13
  5 15 12  7
  3  1 14  2
  9     6  8
 13 11 10  4
step 14
  5 15 12  7
  3  1 14  2
  9  6     8
 13 11 10  4
step 15
  5 15 12  7
  3  1     2
  9  6 14  8
 13 11 10  4
step 16
  5 15 12  7
  3  1  2   
  9  6 14  8
 13 11 10  4
step 17
  5 15 12   
  3  1  2  7
  9  6 14  8
 13 11 10  4
step 18
  5 15    12
  3  1  2  7
  9  6 14  8
 13 11 10  4
step 19
  5    15 12
  3  1  2  7
  9  6 14  8
 13 11 10  4
step 20
  5  1 15 12
  3     2  7
  9  6 14  8
 13 11 10  4
step 21
  5  1 15 12
     3  2  7
  9  6 14  8
 13 11 10  4
step 22
     1 15 12
  5  3  2  7
  9  6 14  8
 13 11 10  4
step 23
  1    15 12
  5  3  2  7
  9  6 14  8
 13 11 10  4
step 24
  1  3 15 12
  5     2  7
  9  6 14  8
 13 11 10  4
step 25
  1  3 15 12
  5  2     7
  9  6 14  8
 13 11 10  4
step 26
  1  3    12
  5  2 15  7
  9  6 14  8
 13 11 10  4
step 27
  1     3 12
  5  2 15  7
  9  6 14  8
 13 11 10  4
step 28
  1  2  3 12
  5    15  7
  9  6 14  8
 13 11 10  4
step 29
  1  2  3 12
  5  6 15  7
  9    14  8
 13 11 10  4
step 30
  1  2  3 12
  5  6 15  7
  9 14     8
 13 11 10  4
step 31
  1  2  3 12
  5  6 15  7
  9 14 10  8
 13 11     4
step 32
  1  2  3 12
  5  6 15  7
  9 14 10  8
 13    11  4
step 33
  1  2  3 12
  5  6 15  7
  9    10  8
 13 14 11  4
step 34
  1  2  3 12
  5  6 15  7
  9 10     8
 13 14 11  4
step 35
  1  2  3 12
  5  6     7
  9 10 15  8
 13 14 11  4
step 36
  1  2  3 12
  5  6  7   
  9 10 15  8
 13 14 11  4
step 37
  1  2  3   
  5  6  7 12
  9 10 15  8
 13 14 11  4
step 38
  1  2     3
  5  6  7 12
  9 10 15  8
 13 14 11  4
step 39
  1  2  7  3
  5  6    12
  9 10 15  8
 13 14 11  4
step 40
  1  2  7  3
  5  6 15 12
  9 10     8
 13 14 11  4
step 41
  1  2  7  3
  5  6 15 12
  9 10  8   
 13 14 11  4
step 42
  1  2  7  3
  5  6 15 12
  9 10  8  4
 13 14 11   
step 43
  1  2  7  3
  5  6 15 12
  9 10  8  4
 13 14    11
step 44
  1  2  7  3
  5  6 15 12
  9 10     4
 13 14  8 11
step 45
  1  2  7  3
  5  6    12
  9 10 15  4
 13 14  8 11
step 46
  1  2  7  3
  5  6 12   
  9 10 15  4
 13 14  8 11
step 47
  1  2  7  3
  5  6 12  4
  9 10 15   
 13 14  8 11
step 48
  1  2  7  3
  5  6 12  4
  9 10    15
 13 14  8 11
step 49
  1  2  7  3
  5  6 12  4
  9 10  8 15
 13 14    11
step 50
  1  2  7  3
  5  6 12  4
  9 10  8 15
 13 14 11   
step 51
  1  2  7  3
  5  6 12  4
  9 10  8   
 13 14 11 15
step 52
  1  2  7  3
  5  6 12  4
  9 10     8
 13 14 11 15
step 53
  1  2  7  3
  5  6     4
  9 10 12  8
 13 14 11 15
step 54
  1  2     3
  5  6  7  4
  9 10 12  8
 13 14 11 15
step 55
  1  2  3   
  5  6  7  4
  9 10 12  8
 13 14 11 15
step 56
  1  2  3  4
  5  6  7   
  9 10 12  8
 13 14 11 15
step 57
  1  2  3  4
  5  6  7  8
  9 10 12   
 13 14 11 15
step 58
  1  2  3  4
  5  6  7  8
  9 10    12
 13 14 11 15
step 59
  1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14    15
step 60
  1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14 15   

Process returned 0 (0x0)   execution time : 5.352 s


Но решение может bыть не оптимальным, по какой-то причине, на первом примере вместо 36 выдаёт 42 шага. Может не совсем правильно реализовал.

Пожалуй, мне это надоело... smile

Добавлено @ 20:57
Цитата(Isaev @  23.11.2010,  19:03 Найти цитируемый пост)
а потом 3х3 это же выведет алгоритм раньше к правильному решению?
Только если получится решаемая комbинация.

Добавлено @ 21:00
Цитата(Isaev @  23.11.2010,  19:03 Найти цитируемый пост)
ну применимо к картам никто не мешает изменить эвристическую оценку к тому же sqrt(dx^2 + dy^2)
sqrt(dx^2 + dy^2) / V(cредняя скорость)
Т.е. надо время считать.


Это сообщение отредактировал(а) Леопольд - 23.11.2010, 21:27


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Леопольд
Дата 23.11.2010, 21:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Master01 @  23.11.2010,  16:21 Найти цитируемый пост)
поскольку dx + dy (манхэттэн-расстояние) всега заведомо больше sqrt(dx^2 + dy^2)


sqrt(dx^2 + dy^2) = S(x, y)
dx + dy = M(x, y)

S(1,1) < S(1,2)
M(1, 1) < M(1,2)
И то и другое должно найти оптимальный путь. Суть в том, что если эвристическая функция менее точна, то, почти наверняка, понадоbиться bольше нодов рассмотреть при поиске.


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Isaev
Дата 23.11.2010, 21:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Леопольд @  23.11.2010,  20:49 Найти цитируемый пост)
Пожалуй, мне это надоело...

это потому, что нет азарта smile не пробовал на hacker.org игры для программистов?
Вот там интерес не пропадает, т.к. кто-то всё равно сделает быстрее, сидишь и думаешь что же можно улучшить, когда вроде и так всё летает smile)))
PM MAIL ICQ   Вверх
Master01
Дата 24.11.2010, 16:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата

ну применимо к картам никто не мешает изменить эвристическую оценку к тому же sqrt(dx^2 + dy^2), если такой путь часто имеет место быть, то оно себя окупит...


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

Я не говорю, что это не верно. Просто прежде чем вводить ту или иную эвристику нужно хорошо подумать smile А для той задачи, что я привёл уже люди хорошо подумали и рекомендовали нам делать так smile.

Цитата

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


Ну так МП так и поступает.

Добавлено через 13 минут и 33 секунды
Цитата(Леопольд @ 23.11.2010,  21:25)
Цитата(Master01 @  23.11.2010,  16:21 Найти цитируемый пост)
поскольку dx + dy (манхэттэн-расстояние) всега заведомо больше sqrt(dx^2 + dy^2)


sqrt(dx^2 + dy^2) = S(x, y)
dx + dy = M(x, y)

S(1,1) < S(1,2)
M(1, 1) < M(1,2)
И то и другое должно найти оптимальный путь. Суть в том, что если эвристическая функция менее точна, то, почти наверняка, понадоbиться bольше нодов рассмотреть при поиске.

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

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

Цитата

Суть в том, что если эвристическая функция менее точна, то, почти наверняка, понадоbиться bольше нодов рассмотреть при поиске.


нет, только если она не точно в меньшую  сторону, т.е. недооценивает расстояние. Чем меньше вклад эвристического приближения h(x) в общую оценку f(x) = g(x) + h(x), тем алгоритм менее направлен, т.е. просматривает больше узлов.

С другой стороны переоценка - добавляет направленности, но теряется точность, т.е. не гарантируется все те свойства, описанные выше.
PM MAIL   Вверх
Леопольд
Дата 24.11.2010, 17:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Master01 @  24.11.2010,  16:11 Найти цитируемый пост)
манхэттен не переоценит расстояние только если
Это не важно. Главное что для по разному удалённых точек на карте, манхэттен bудет давать разную оценку, для дискретной карты, он подходит лучше (даже если можно передвигаться наискосок). При этом для той, которая bлиже, цена bудет меньше. Для эвристики bольшего не надо, т.е. bудет найден оптимальный путь (это как в пятнашках, можно посчитать количество костяшек, не на своём месте). Но, скорее всего, придётся проверить bольшее количество нодов.

Смысл эвристки не в том что-bы дать реальную оценку предстоящего пути (оbычно это невозможно, иначе нет смысла в алгоритме), а в том, что-bы указать, какие состояния нужно проверить прежде других, что-bы алгоритм искал решение "по направлению к цели" прежде всего. Чем точнее эвристика, тем меньше нодов bудет проверенно. (третий раз повторю, на всякий пожарный, авось не проигнорируешь в этот раз...) 

Пройденное расстояние, желательно оbязательно надо оценивать так же по тому же принципу как и предстоящее (тогда не bудет переоценки расстояния).


Это сообщение отредактировал(а) Леопольд - 25.11.2010, 05:52


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Master01
Дата 24.11.2010, 22:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Леопольд @ 24.11.2010,  17:50)
Цитата(Master01 @  24.11.2010,  16:11 Найти цитируемый пост)
манхэттен не переоценит расстояние только если
Это не важно.

Леопольд, прокомментирую только первое ваше предложение, т.к. дальше вы там что-то красных букв много понаписали... да и смыла нет.

Вот, вам цитата из википедии

Функция h(x) должна быть допустимой эвристической оценкой, то есть не должна переоценивать расстояния к целевой вершине

Вот ещё из буржуйской, если инфа в русской вызывает сомнения

The h(x) part of the f(x) function must be an admissible heuristic; that is, it must not overestimate the distance to the goal

Если вы отвечаете мне "не важно" на мои слова про "переоценку" расстояния, то значит, простите, но это скорее всего вы что-то проигнорировали в моих предыдущих постах.

Добавлено через 14 минут и 35 секунд
Цитата

Пройденное расстояние, желательно оценивать так же как и предстоящее


Вообще не верно по сути. Пройденное растояние можно измерить т.к. вы его прошли. А предстоящее можно только угадать, потому что измерять нечего. О какой унификации вы тут говорите, я вообще не понимаю.
PM MAIL   Вверх
Леопольд
Дата 25.11.2010, 03:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Master01 @  24.11.2010,  22:22 Найти цитируемый пост)
Вообще не верно по сути. Пройденное растояние можно измерить т.к. вы его прошли.
Здесь видимо недопонимание, я изменил цитируемую строку, перечитайте.
Т.е. я имел ввиду что оценивать пройденное расстояние надо по тому же принципу что и предстоящее иначе, действительно можно "неугадать" предстоящее.

Цитата(Master01 @  24.11.2010,  22:22 Найти цитируемый пост)
Вот, вам цитата из википедии
Вот вам результат исполнения, можете проверить сами...
Решётки - препятствия. Плюсиками отмечено найденное решение. Точками, остальные рассмотренные состояния, не вошедшие в оптимальный путь. Проbел - не рассматривалось:

dx + dy
Код
++###################
..++++..............#
#...#.+###....#.###.#
#...#..+.#....#...#.#
#...#...+.....#####.#
#...#....+..........#
#...#.....+##########
#####......+++++....#
#   ....#..###.#+...#
# ###...#....#.#+...#
# # #...#.#..#.##+..#
# # #.....#..#...+..#
# # #...#.#..####.+.#
#   #.....#........+.
###################.+
path length    = 22
expanded nodes = 175

sqrt(pow(dx, 2) + pow(dy, 2))
Код
+.###################
.+..+.....          #
#.++#+.###    # ### #
#...#.+..#..  #   # #
#...#..+......##### #
#...#...+.....      #
#...#....+.##########
##### ....++++..    #
#      .#..###+#    #
# ###   #....#+#    #
# # #   #.#..#+##.. #
# # #     #..#.++...#
# # #   # #..####+..#
#   #     #     ..++.
###################.+
path length    = 22
expanded nodes = 104

Цитата(Master01 @  24.11.2010,  16:11 Найти цитируемый пост)
Манхэттен не переоценит расстояние только если при движении к цели вам нужно сначало спуститься по вертикали до нужной вертикали, а потом строго горизонтально двигаться  уже до цели вправо или влево (ну или ещё там где-то петлять). Во всех остальных случаях расстояние будет переоцениным. т.е. минимальность пути не будет гарантирована. 

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

Код
#include <cstring>
#include <iostream>

#include "astar.hpp"

enum {height = 15, width = 21};

char map[height][width + 2] =
{
    "+ ###################\n",
    "                    #\n",
    "#   #  ###    # ### #\n",
    "#   #    #    #   # #\n",
    "#   #         ##### #\n",
    "#   #               #\n",
    "#   #      ##########\n",
    "#####               #\n",
    "#       #  ### #    #\n",
    "# ###   #    # #    #\n",
    "# # #   # #  # ##   #\n",
    "# # #     #  #      #\n",
    "# # #   # #  ####   #\n",
    "#   #     #          \n",
    "################### +\n",
};

std::size_t expandedNodes = 0;

struct Node
{
    struct Pos
    {
        Pos(std::size_t i_, std::size_t j_) : i(i_), j(j_) {}
        std::size_t i;
        std::size_t j;
    } m_state;

    Node(std::size_t i, std::size_t j) : m_state(i, j) {}

    Node(Node const& rhs) : m_state(rhs.m_state) {}

    Node& operator= (Node const& rhs) {
        ::memcpy(&this->m_state, &rhs.m_state, sizeof(Pos));
        return *this;
    }

//    Node() {}

    bool operator< (Node const& rsh) const
    {
        return ::memcmp(&this->m_state, &rsh.m_state, sizeof(Pos)) < 0;
    }

    bool operator== (Node const& rsh) const
    {
        return ::memcmp(&this->m_state, &rsh.m_state, sizeof(Pos)) == 0;
    }

    std::unique_ptr<std::vector<Node>> expand() const
    {
        std::unique_ptr<std::vector<Node>> result(new std::vector<Node>);

        std::size_t top = 0 < this->m_state.i ? m_state.i - 1  : 0;
        std::size_t const bottom = this->m_state.i < height - 1 ? m_state.i + 1 : height - 1;

        for(; top <= bottom; ++top)
        {
            std::size_t left = 0 < this->m_state.j ? m_state.j - 1 : 0;
            std::size_t const right = this->m_state.j < width - 1 ? m_state.j + 1 : width - 1;

            for(; left <= right; ++left)
            {
                if(map[top][left] != '#')
                {
                    if(map[top][left] != '.')
                    {
                        ++expandedNodes;
                        map[top][left] = '.';
                        result->push_back(Node(top, left));
                    }
                }
            }
        }

        return move(result);
    }

    typedef double HCost;

//    static Node::HCost heurisicCost(Node const& from, Node const& to)
//    {
//        double const dx = from.m_state.i < to.m_state.i ? to.m_state.i - from.m_state.i : from.m_state.i - to.m_state.i;
//        double const dy = from.m_state.j < to.m_state.j ? to.m_state.j - from.m_state.j : from.m_state.j - to.m_state.j ;
//
//        return dx + dy;
//    }

    static Node::HCost heurisicCost(Node const& from, Node const& to)
    {
        double const dx = from.m_state.i < to.m_state.i ? to.m_state.i - from.m_state.i : from.m_state.i - to.m_state.i;
        double const dy = from.m_state.j < to.m_state.j ? to.m_state.j - from.m_state.j : from.m_state.j - to.m_state.j ;

        return ::sqrt(::pow(dx, 2) + ::pow(dy, 2));
    }
};




int main()
{
    auto result = aStarSearch(Node(0, 0), Node(14, 20));

    for(auto it = result->begin(); it != result->end(); ++it)
    {
        map[it->m_state.i][it->m_state.j] = '+';
    }

    for(std::size_t i = 0; i < height; ++i)
        std::cout << map[i];

    std::cout << "path length    = " << result->size() - 1 << '\n';
    std::cout << "expanded nodes = " << expandedNodes << std::flush;

    return 0;
}


Цитата(Master01 @  24.11.2010,  22:22 Найти цитируемый пост)
Леопольд, прокомментирую только первое ваше предложение, т.к. дальше вы там что-то красных букв много понаписали...
Если выдрать предложение из контекста, то у него может запросто измениться смысл на противоположный. Может неспроста там bуковки красные?

Это сообщение отредактировал(а) Леопольд - 25.11.2010, 09:45


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Леопольд
Дата 25.11.2010, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Так, наверное, понятнее в чём разница:
r() - стоимость пройденного пути
h() - эвристическая оценка

r() = dx + dy
h() = dx + dy 
Код
#   .+..........   #
#   .+..........   #
#   .+..........   #
#   .+..........   #
#   .+..........   #
#   .+..........   #
#   ..+.........   #
#   ...+........   #
#   ....+.......   #
#   .....+......   #
#   ......+.....   #
#   .......+....   #
#   ........+...   #
#   .........+..   #
#   ..........+.   #
path length    = 14
expanded nodes = 180
http://liveworkspace.org/code/06c2ad0d88bf9ef8488ff7718b2f924c

r() = sqrt(pow(dx, 2) + pow(dy, 2))
h() = sqrt(pow(dx, 2) + pow(dy, 2))
Код
#   .+...          #
#   ..+...         #
#   ...+...        #
#    ...+...       #
#     ...+...      #
#      ...+..      #
#       ..+...     #
#        ..+...    #
#        ..+....   #
#         ..+...   #
#         ..+...   #
#          ..+..   #
#          ..+..   #
#           .+..   #
#           ..+.   #
path length    = 14
expanded nodes = 87
http://liveworkspace.org/code/373a804d7d5788718b08fc4ab201a41f

r() = dx + dy
h() = sqrt(pow(dx, 2) + pow(dy, 2)) 
Код
#....+..........   #
#....+..........   #
#....+..........   #
#....+..........   #
#....+..........   #
#....+..........   #
#.....+.........   #
# .....+........   #
# ......+.......   #
# .......+......   #
#  .......+.....   #
#  ........+....   #
#  .........+...   #
#   .........+..   #
#   ..........+.   #
path length    = 14
expanded nodes = 210
http://liveworkspace.org/code/829322bd34ab3183265c494608421bca
h() < r() - рассматриваются сперва те ноды, которые ближе к старту (большее количество нодов)

r() = sqrt(pow(dx, 2) + pow(dy, 2)) 
h() = dx + dy 
Код
#   .+..           #
#   ..+..          #
#    ..+..         #
#     ..+..        #
#      ..+..       #
#       ..+..      #
#        ..+..     #
#         ..+..    #
#          ..+..   #
#           ..+.   #
#            .+.   #
#            .+.   #
#            .+.   #
#            .+.   #
#            .+.   #
path length    = 14
expanded nodes = 63
http://liveworkspace.org/code/96359f2f06134f0961a244ecbdbd5c2b
h() > r() - рассматриваются сперва те ноды, которые ближе к цели (меньшее количество нодов)

h() = r(), гарантирует оптимальность решения (наименьший путь)
насчёт h() < r(), не уверен, интуитивно кажется то решение оптимальное
h() > r(), быстрее поиск, но нет гарантии оптимального решения

Это сообщение отредактировал(а) Леопольд - 25.11.2010, 11:26


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Леопольд
Дата 25.11.2010, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Забавно. Увеличил в 1.5 раза h() относительно r() в пятнашках и получил оптимальный результат (51 шаг) менее чем за 3 секунды. 
http://liveworkspace.org/code/7e1472ca6b32...5357e0d330320c3

Если в два раза, то решает за  61 ход менее чем за секунду...
http://liveworkspace.org/code/58e9e2b3536e...f06f846a39dcafc

В пять раз smile:
Код

step 93
  1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14 15  
execution time: 0.1163
Если нужно решить хоть как-то, но очень быстро. Алгоритм быстрее продвигается к цели, пренебрегая точностью...

Это сообщение отредактировал(а) Леопольд - 25.11.2010, 12:56


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Master01
Дата 25.11.2010, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата

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


Цитата


нет, только если она не точно в меньшую  сторону, т.е. недооценивает расстояние. Чем меньше вклад эвристического приближения h(x) в общую оценку f(x) = g(x) + h(x), тем алгоритм менее направлен, т.е. просматривает больше узлов.

С другой стороны переоценка - добавляет направленности, но теряется точность, т.е. не гарантируется все те свойства, описанные выше.


Леопольд, ну вот словами "я же говорил" этого не передать ...
PM MAIL   Вверх
Леопольд
Дата 25.11.2010, 14:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Master01 @  25.11.2010,  13:38 Найти цитируемый пост)
но теряется точность
Эмпирически выявил что точность теряется после определённого порога переоценки. Если эвристику считать так (h() * (1 + 0.01 * r()), то потерь точности не наблюдается... До тех пор, пока не пересечёшь некий определённый порог, оптимальность сохраняется, скорость увеличивается.

Цитата(Master01 @  25.11.2010,  13:38 Найти цитируемый пост)
Леопольд, ну вот словами "я же говорил" этого не передать ... 
А я разве с этим спорил? Но вот ещё что было сказано:
Цитата(Master01 @  24.11.2010,  16:11 Найти цитируемый пост)
Манхэттен не переоценит расстояние только если при движении к цели вам нужно сначало спуститься по вертикали до нужной вертикали, а потом строго горизонтально двигаться  уже до цели вправо или влево (ну или ещё там где-то петлять). Во всех остальных случаях расстояние будет переоцениным. т.е. минимальность пути не будет гарантирована. 
Я это понял так, что если использовать "манхэттен", то минимальность пути не будет гарантирована. Я не согласился, потому что, это справедливо только при условии, что пройденный путь оценивается иначе (например, как расстояние по прямой, о чём было упомянуто вскользь, в ваших предыдущих постах). Нельзя замалчивать подобные необходимые условия. Перечитайте ваше утверждение ещё раз...

Плюс к этому, не раз отметил что чем менее "подходяще" оценивается путь и эвристика (предполагается что одинаковым способом) тем больше узлов придётся просчитать, однако решение, останется оптимальным. Т.е. можно обеспечить направленность не только "вмИняемой" переоценкой, но и более подходящим способом оценки (без переоценки эвристики), что гарантирует оптимальный результат. На что "услышал" категоричное
Цитата(Master01 @  24.11.2010,  16:11 Найти цитируемый пост)
Нет. 
А так как делать мне было нефиг, я ударился в полемику.  smile

P.S. Когда ж мне надоест писать одно и то же разными словами, вот ведь зануда...


Это сообщение отредактировал(а) Леопольд - 25.11.2010, 15:10


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Master01
Дата 25.11.2010, 16:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата

Эмпирически выявил что точность теряется после определённого порога переоценки. Если эвристику считать так (h() * (1 + 0.01 * r()), то потерь точности не наблюдается... До тех пор, пока не пересечёшь некий определённый порог, оптимальность сохраняется, скорость увеличивается.


Вы частным доказываете общее. Что уже делает все ваши выводы заведомо неверными.

Цитата

А я разве с этим спорил? Но вот ещё что было сказано:


определённо

Цитата

Я это понял так, что если использовать "манхэттен", то минимальность пути не будет гарантирована


Вы поняли правильно.

Цитата

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


Вот это то, что вы понять не можете. Ваша догадка h(x) Манхэттэн - это есть некоторое среднее ожидаемое расстояние, т.е. значит, что реальное расстояние может быть как больше, так и меньше. 
Но если случай, когда реальное расстояние может быть меньше существует (т.е. H() переоценила расстояние), то, следовательно, вы не можете быть уверены в минимальности найденного пути.
Единственный выход - заложить в h() заведомо наименьшее возможное расстояние - т.е. прямую. Только в этом случае вы гарантировано получите минимальный путь. Но поскольку dx + dy > sqrt(dx^2 + dy^2) то алгоритм станет менее направленным - замедлиться. Поэтому я и написал, что нужен балланс.

Пройденный путь можно измерить, т.к. мы его уже прошли, понимайте это как "измерили линейкой".
Ожидаемый остаток - прогноз, основанный на некоторых знаниях о пространстве.

Так вот между вычислением g(x) и h(x) ровно столько же общего как и в измерении текущей температуры и предсказании температуры на завтра.

Цитата

Плюс к этому, не раз отметил что чем менее "подходяще" оценивается путь и эвристика (предполагается что одинаковым способом) тем больше узлов придётся просчитать, однако решение, останется оптимальным


Вы в каких-то терминах выражаетесь неоределённых. Что значит "менее подходяще"? 
Если вы о точности, то вы сами сказали, что если эвристика переоценивает оставщееся расстояние то поиск "h() > r(), быстрее поиск, но нет гарантии оптимального решения".

Цитата

Т.е. можно обеспечить направленность не только "вмИняемой" переоценкой, но и более подходящим способом оценки (без переоценки эвристики)


Туфтология. "Вминяемой переоценкой без переоценки". Вы сами понимаете то свою точку зрения, которую защищаете? Кроме того, вы противопоставляете одной субъективной оценке "вминяемой" другую "более подходящим". Ерунда.

А
Цитата

 так как делать мне было нефиг, я ударился в полемику


Вот именно.

Цитата

P.S. Когда ж мне надоест писать одно и то же разными словами, вот ведь зануда...


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



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


Шустрый
*


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

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



Цитата(Леопольд @  25.11.2010,  12:52 Найти цитируемый пост)
Увеличил в 1.5 раза h() относительно r() в пятнашках и получил оптимальный результат (51 шаг) менее чем за 3 секунды. 

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

Цитата(Master01 @  25.11.2010,  16:43 Найти цитируемый пост)
Вы частным доказываете общее.

А вы часто цепляетесь к словам, что сводит большинство споров к трате времени, т.к. по сути говорите об одном и том же, а каждый доказывает своё. smile

Это сообщение отредактировал(а) Isaev - 25.11.2010, 17:07
PM MAIL ICQ   Вверх
Леопольд
Дата 25.11.2010, 17:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Master01 @  25.11.2010,  16:43 Найти цитируемый пост)
Вы частным доказываете общее.
Во первых, не доказываю, я же сказал, эмпирически, т.е. не исключаю что это возможно... Несколько различных комbинаций (штук пять) дали оптимальный результат с "неbольшой" переоценкой эвристики. Возникло ощущение, что есть зависимость от пройденного пути. Надо bудет сгенерировать штук 5000, и проверить на них, если все дадут оптимальный результат, это уже что-то...
Во вторых, пройденное расстояние можно считать как угодно, хоть bы по потраченному на него времени, или с учётом местности (по песку медленнее чем по асфальту) и т.п. и т.д.. Как bы не рассчитывался "пройденный путь" (не оbязательно bуквально путь, просто цепь шагов), эвристика, которая рассчитывается по тому же принципу, даёт оптимальный результат. Т.е. пройденный путь можно считать как манхэтеннское, как прямую линию линейкой, как время... Не исключено, что есть ещё варианты. Что вы зациклились на одном и том же?

Цитата(Master01 @  25.11.2010,  16:43 Найти цитируемый пост)
Вы поняли правильно.
Это уже похоже на bред... Вы комментируете только вступление, которое bез контекста имеет другой смысл, не тот который я в него вложил.
Цитата(Master01 @  25.11.2010,  16:43 Найти цитируемый пост)
Но если случай, когда реальное расстояние может быть меньше существует (т.е. H() переоценила расстояние), то, следовательно, вы не можете быть уверены в минимальности найденного пути.
Может bыть посмотрите уже код? Честно говоря я устал оbъяснять очевидное, такое ощущение, что вы читаете только то что вам надо, остальное просто игнорируете.  Хотя, можете остаться при своём мнении, мне всё равно...

Цитата(Master01 @  25.11.2010,  16:43 Найти цитируемый пост)
Туфтология. "Вминяемой переоценкой без переоценки".
Никоrда не мог понять, зачем выдирать отдельные слова из предложения, составлять из них что-то bессмысленное и приписывать авторство другому человеку. Типичный троллинг...

Цитата(Master01 @  25.11.2010,  16:43 Найти цитируемый пост)
Я не имею привычки учить людей тому, в чём, считаю, не разбираюсь.
Я ведь не просил меня ничему учить. Всё что вы мне сказали я понял и оbъяснил то, что вы упустили. Вот вы понять отказываетесь, а это уже не моя проbлема...
Хотя, я не отказался bы посмотреть на реализацию A*, которая куbик Руbика соbирает. Потянете? Вы же, вроде как, "соbаку съели", должно bыть несложно...

Добавлено @ 17:34
Цитата(Isaev @  25.11.2010,  17:03 Найти цитируемый пост)
оптимальность пуки не критична
 smile 


Это сообщение отредактировал(а) Леопольд - 25.11.2010, 18:24


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
ufna
Дата 25.11.2010, 18:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



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

Не вижу проблем для использования h=sqrt(x^2+y^2), однако если нужны сверхбыстрые решения, то можно вводить таблицу кэша значений эмпирики, если есть более четкие условия на количество точек и т.п., да и вообще есть разные приемы модернизации алгоримта для решения конкретной задачи.

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

Очереди нужны, open и close, причем оптимизированные для действий по этому алгоритму.


Это сообщение отредактировал(а) ufna - 25.11.2010, 18:59
PM MAIL WWW Skype   Вверх
Леопольд
Дата 25.11.2010, 21:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Леопольд @  25.11.2010,  17:21 Найти цитируемый пост)
Надо bудет сгенерировать штук 5000, и проверить на них, если все дадут оптимальный результат, это уже что-то...
 Сгенерил 50000 нодов (пятнашки), даже если 90% оказались одинаковые, что крайне маловероятно, то почти наверняка,5000 шт. bыли разные. Для всеx 50000 сгенерённых, с неbольшой переоценкой эвристики, зависящей от пройденного пути, bыл найден оптимальный путь. Интересно, почему...
Код
#include <random>
#include <functional>

std::uniform_int_distribution<int> distribution(0, 4);
std::mt19937 engine;
auto generator = std::bind(distribution, engine);

void generateStartPoint(void)
{
    auto nodes = Node(start).expand();

    ::memcpy(start, (*nodes)[generator() % nodes->size()].m_state, sizeof(start));
}

int main()
{
    for(std::size_t i = 1; i < 50000; ++i)
    {
        auto resultCommmon = aStarSearch(Node(start), Node(goal));
        auto resultBoosted = aStarSearchBoosted(Node(start), Node(goal));

        if(resultCommmon->size() != resultBoosted->size())
        {
            resultBoosted->begin()->print();
            std::cout << "unmatch " << i;
            std::cout << std::flush;
        }

        if(resultCommmon->size() > 35) //что-bы не ждать месяц
        {
            ::memcpy(start, pattern, sizeof(start));
        }

        generateStartPoint();
    }

    return 0;
}


h() эвристика, r() пройденный путь
переоценка эвристики = h() * (1 + 0.01 * r())

На дискретной карте, не работает. Показалось...


Это сообщение отредактировал(а) Леопольд - 26.11.2010, 10:52


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Master01
Дата 25.11.2010, 21:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата

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


Ufna, простите, но обход в ширину проверяет вершины в том порядке в каком их находит, т.е. не сортирует их по стоимости. Алгоритм Дейкстры вводит такую сортировку, но не использует эвристику.

Я имел ввиду, что при нулевой эвристике h(x)=0 Astar становится алгоритмом Дейкстры, поскольку оценивает только реальную стоимость пути при выборе "наилучшей" вершины.

В остальном, я с вами согласен.
PM MAIL   Вверх
Леопольд
Дата 25.11.2010, 21:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Master01 @  25.11.2010,  21:35 Найти цитируемый пост)
обход в ширину проверяет вершины в том порядке в каком их находит, т.е. не сортирует их по стоимости.
Их не надо сортировать по стоимости. Просто пихать в очередь. Поиск в ширину, сперва рассматривает bлижайшие вершины, естественно, их стоимость меньше чем стоимость вершин, порождённых из них. A* это поиск в ширину с эвристикой, которая задаёт направление.


Это сообщение отредактировал(а) Леопольд - 25.11.2010, 21:46


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
ufna
Дата 25.11.2010, 21:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Master01,

Да, Вы правы, по сути алгоритм Дейкстры - частный случай А-стар с h(x) = 0 для всех х. Хотя реализация у них разная, я говорил именно в этом ключе - т.к. Дейкстра работает как d(x,y), и имеет свои требования к памяти и прочему.
PM MAIL WWW Skype   Вверх
Master01
Дата 25.11.2010, 23:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Леопольд @  25.11.2010,  17:21 Найти цитируемый пост)
Цитата(Master01 @  25.11.2010,  16:43 Найти цитируемый пост)
Туфтология. "Вминяемой переоценкой без переоценки".
Никоrда не мог понять, зачем выдирать отдельные слова из предложения, составлять из них что-то bессмысленное и приписывать авторство другому человеку. Типичный троллинг...


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


Цитата(Леопольд @  25.11.2010,  17:21 Найти цитируемый пост)
Цитата(Master01 @  25.11.2010,  16:43 Найти цитируемый пост)
Вы поняли правильно.
Это уже похоже на bред... Вы комментируете только вступление, которое bез контекста имеет другой смысл, не тот который я в него вложил.


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

Остальное не комментирую, как не имеющее отношение к делу.
PM MAIL   Вверх
Леопольд
Дата 26.11.2010, 10:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 10
Всего: 13



Цитата(Master01 @  25.11.2010,  23:28 Найти цитируемый пост)
И дальше все ваши рассуждения - неверны.
Прям таки все, или всё же какие-то конкретно?



--------------------
вопросов больше чем ответов
PM MAIL   Вверх
Isaev
Дата 26.11.2010, 22:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Master01, Вы бы, чтобы не быть голословным, раз уж "на этом собаку съели" привели бы пример, который работает быстрее, чем у Леопольда, и мы бы дружно задумались, что возможно и правда мы все не правы...  smile  
PM MAIL ICQ   Вверх
Isaev
Дата 6.5.2013, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Леопольд @  22.11.2010,  12:53 Найти цитируемый пост)
я сейчас С++0x осваиваю, на нём код алгоритма понятнее:

Охотно верю, когда остваиваете smile
Может вы совершенно случайно можете это на Delphi написать? Я был бы крайне признателен, т.к. этот язык мне ближе, если честно
то что писали на яве, отлично работало, а сейчас решил побаловаться в Delphi и никак не могу портировать код туда  smile 
PM MAIL ICQ   Вверх
mihail2244
Дата 9.5.2013, 14:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



НОвый проект
Твоя Кострома
PM MAIL WWW Skype YIM MSN   Вверх
Isaev
Дата 5.7.2018, 11:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Ведь можно запустить его в два потока (для каждой вершины свой) и проверять пересечение в общей вершине в процессе поиска. 
Даст ли это реальный прирост скорости на больших графах?
PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
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.2673 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


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

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