Название: Удалить ближайших Отправлено: Igors от Май 27, 2012, 13:28 Добрый день
Есть массив точек (int x, y), нужно удалить некоторые так чтобы расстояние между любыми двумя из оставшихся Спасибо Edit: извиняюсь, описАлся, правильно "не меньше заданного" (т.е. прореживание) Название: Re: Удалить ближайших Отправлено: Racheengel от Май 31, 2012, 21:59 наверное, нету, придется эти 10 строчек вручную писать :(
а STL вообще бесполезен, когда есть Qt :) Название: Re: Удалить ближайших Отправлено: Igors от Июнь 01, 2012, 14:52 наверное, нету, придется эти 10 строчек вручную писать :( Ну тогда может есть в Qt? И что-то у меня получается намного больше 100 строк (не говоря уже о 10) :'(а STL вообще бесполезен, когда есть Qt :) Название: Re: Удалить ближайших Отправлено: Bepec от Июнь 01, 2012, 15:01 update: чуть вник.
А в чём проблема то? Вроде (неуверен), если брать элемент, проверять все остальные на промежуток между ним. Не входящие удалять. Следующий элемент и цикл погнали. Вопрос - а дополнительных условий нет? К примеру на количество оставшихся? Потому что вроде самое простое - если первая точка не сходится хоть с одной точкой, значит её надо удалять(первую точку). Если хоть 1 точка с ней сходится - надо удалять остальные не входящие в радиус. PS Тут вопрос уже, что таких массивов может быть несколько на плоскости. А так, без дополнительных условий всё просто. Название: Re: Удалить ближайших Отправлено: Akon от Июнь 01, 2012, 18:06 Другими словами - на плоскости кругом диаметра D нужно накрыть точки, непокрытые точки удалить. Так? В общем случае решений то много, и нужны доп условия, например, максимизировать количество накрытых точек.
Примитивный вариант - чесать циклом все точки и найти максимальную плотность. А вот если имеется какая-нибудь закономерность в распределении точек по плоскости - то будет задача поиска экстремума (методы решения - от градиентного поиска до всяких там генетических алгоритмов). Название: Re: Удалить ближайших Отправлено: Igors от Июнь 01, 2012, 19:12 А в чём проблема то? Так а сколько времени это будет работать напр на 100k точек? Вроде (неуверен), если брать элемент, проверять все остальные на промежуток между ним. Не входящие удалять. Следующий элемент и цикл погнали. Вопрос - а дополнительных условий нет? К примеру на количество оставшихся? Можно сказать что нет. Понятно что если точка не была близка с никакой доугой - то нечего ее было удалять. А так никакого "оптимального" удаления не ищется - любое разумное Другими словами - на плоскости кругом диаметра D нужно накрыть точки, непокрытые точки удалить. Так? Нет, наоборот :) Это я оговорился, виноват, подправил (см первый пост)Название: Re: Удалить ближайших Отправлено: Serr500 от Июнь 01, 2012, 21:10 Ну тогда может есть в Qt? И что-то у меня получается намного больше 100 строк (не говоря уже о 10) :'( А чего так много-то? Код: typedef Point; // точка Название: Re: Удалить ближайших Отправлено: Igors от Июнь 01, 2012, 21:54 А чего так много-то? Это вариант Вереса только еще хуже т.к. erase - дорогая операция. Ну и с QVector вылетит - его итератор становится невалидным после erase (хотя это неважно)Код: typedef Point; // точка Название: Re: Удалить ближайших Отправлено: Akon от Июнь 01, 2012, 22:40 Наложить на плоскость регулярную решетку, точки, покрытые решеткой удалить, в неплотностях решетки может оказаться >1 точки, поэтому вторым проходом оставляем только одну любую точку в каждой неплотности.
Название: Re: Удалить ближайших Отправлено: Igors от Июнь 02, 2012, 09:14 Наложить на плоскость регулярную решетку, точки, покрытые решеткой удалить, в неплотностях решетки может оказаться >1 точки, поэтому вторым проходом оставляем только одну любую точку в каждой неплотности. А что это за "неплотности" такие? Расскажите подробнее, лучше с псевдокодомНазвание: Re: Удалить ближайших Отправлено: Serr500 от Июнь 02, 2012, 10:34 Это вариант Вереса только еще хуже т.к. erase - дорогая операция. Ну и с QVector вылетит - его итератор становится невалидным после erase (хотя это неважно) Почему это он невалидный? erase() вернёт следующий валидный итератор, который мы и присвоим J. Итератор I останется валидным, поскольку все J "дальше" чем I.По поводу дороговизны erase полностью согласен. Если нужно быстрее, то можно метить элементы для удаления каким-нибудь явно недопустимым значением, после прохода всех циклов создать пустой массив и перекопировать в него оставшиеся элементы. Название: Re: Удалить ближайших Отправлено: Igors от Июнь 02, 2012, 11:06 Почему это он невалидный? erase() вернёт следующий валидный итератор, который мы и присвоим J. Итератор I останется валидным, поскольку все J "дальше" чем I. Вы правыПо поводу дороговизны erase полностью согласен. Если нужно быстрее, то можно метить элементы для удаления каким-нибудь явно недопустимым значением, после прохода всех циклов создать пустой массив и перекопировать в него оставшиеся элементы. Копировать необязательно, можно напр remove_if. Но это не решает главной проблемы - перебор "каждый с каждым" может работать часамиНазвание: Re: Удалить ближайших Отправлено: Serr500 от Июнь 02, 2012, 11:10 Насколько я понял, точки находятся на плоскости, т.е. имеют две координаты - x,y. По какой формуле вычисляется расстояние между точками?
Название: Re: Удалить ближайших Отправлено: Serr500 от Июнь 02, 2012, 11:22 Если используется евклидова метрика на плоскости
Код: rho((x1,y2), (x2,y2)) = sqrt((x1-x2)^2+(y1-y2)^2) Код: (abs(x1-x2) < D/sqrt(2)) or (abs(y1-y2) < D/sqrt(2)) Название: Re: Удалить ближайших Отправлено: Igors от Июнь 02, 2012, 11:42 Код: (abs(x1-x2) < D/sqrt(2)) or (abs(y1-y2) < D/sqrt(2)) Код: qreal D2 = D * D; Название: Re: Удалить ближайших Отправлено: vregess от Июнь 02, 2012, 13:22 Я могу ошибаться, но возможно подойдут вот эти ребята:
1) Spatial database (http://en.wikipedia.org/wiki/Spatial_database#Spatial_Index) 2) K-D-tree (http://en.wikipedia.org/wiki/K-d_tree) 3) M-tree (http://en.wikipedia.org/wiki/M-tree) 4) Quadtree (http://en.wikipedia.org/wiki/Quadtree) 5) R-tree (http://en.wikipedia.org/wiki/R-tree) мб M-tree самый правильный. Вот тут java applet с примером есть: http://www.cmarschner.net/mtree.html Я совершенно не разбираюсь в этих алгоритмах, просто однажды просили поискать. Название: Re: Удалить ближайших Отправлено: Igors от Июнь 02, 2012, 17:24 Я могу ошибаться, но возможно подойдут вот эти ребята: Ребята сильные, но ни один из них не выглядит ни простым ни дешевым для реализации. Плюс смущает одно обстоятельство - нужно ведь просто проредить/отфильтровать (а совсем не весь функционал), хочется обойтись без полномасштабного построения дерева.В любом случае спасибо за подборочку Название: Re: Удалить ближайших Отправлено: vregess от Июнь 02, 2012, 21:59 Ребята сильные, но ни один из них не выглядит ни простым ни дешевым для реализации. Плюс смущает одно обстоятельство - нужно ведь просто проредить/отфильтровать (а совсем не весь функционал), хочется обойтись без полномасштабного построения дерева. Если просто - то перебор, если быстро, то не просто) Но я понимаю. Эти алгоритмы не такие простые, для "простой" задачи. Я и сам бы не рвался их использовать, мб как вариант для будущих улучшений. Название: Re: Удалить ближайших Отправлено: Akon от Июнь 03, 2012, 16:11 Цитировать Наложить на плоскость регулярную решетку, точки, покрытые решеткой удалить, в неплотностях решетки может оказаться >1 точки, поэтому вторым проходом оставляем только одну любую точку в каждой неплотности. Берем круг, к нему приставляем еще круг и т.д. по плоскости. Получается решетка, между кругами есть промежутки (неплотности). Коордтнаты центров кругов известны. Алгоритм исключения точек простейший.Название: Re: Удалить ближайших Отправлено: Igors от Июнь 03, 2012, 17:41 Берем круг, к нему приставляем еще круг и т.д. по плоскости. Получается решетка, между кругами есть промежутки (неплотности). Коордтнаты центров кругов известны. Алгоритм исключения точек простейший. Так что, если "взяли круг" - так уже мы знаем какие точки в него попадут? Или можем это быстро определить? Не вижу каким образом. Также: если я правильно понял, центры кругов образуют регулярную решетку, и полагается что в 1 круге - не более 1 точки. Тогда 2 близкие точки могут быть в соседних кругах, и одна из них не будет удалена вторым проходом по "неплотностям" Название: Re: Удалить ближайших Отправлено: Disa от Июнь 09, 2012, 13:16 Мб попробовать решение по аналогии с closest pair algorithm?
То есть 1) Делить множество пополам относительно некого pivot (по x-вой координате). Pivot - это то, что в русскоязычной литературе называется компаранд (по ссылке - средняя точка). 2) Рекурсивно вызывать функцию для каждой из двух половинок, где "внизу" дерева рекурсии проверяем расстояние между ними, если оно меньше - удаляем точки (тут h - величина фиксированная нами). 3) Аналогично поменять функцию объединения(split function, по ссылке это стадия объединения), то есть множество C(pi) так же для фиксированного h. Время работы - это сумма времени работы рекурсивных вызовов + функция объединения. http://e-maxx.ru/algo/nearest_points Название: Re: Удалить ближайших Отправлено: Igors от Июнь 09, 2012, 14:16 Мб попробовать решение по аналогии с closest pair algorithm? Так я пробовал :) На сильном прореживании (когда расстояние D мало) - все очень прилично, но при бОльших D опять сваливаемся в перебор. В closest pair этой проблемы нет - ищем минимальное, ну D и уменьшается автоматычно То есть |