0

EuclideanDistance(P,Q)2つの点P、Qとデルタが与えられた場合、同値関係〜=を定義しました。ここで、 <=デルタの場合はP〜=Qです。ここで、 n個のポイントのセットSが与えられた場合、例ではS =(A、B、C、D、E、F)およびn = 6(実際のポイントは実際にはセグメントの端点です)、次のようなアルゴリズムがありますか?セットのパーティションを見つけるために、平均的なケースでO(n ^ 2)よりも複雑さが優れていますか(サブセットの代表的な要素は重要ではありません)?

この問題の理論的定義を見つける試みはこれまで成功していませんでした。k-meansクラスタリング、最近傍探索など、私には別の問題のようです。写真は、アプリケーションで何をする必要があるかを示しています。

ヒントはありますか?ありがとう

代替テキスト

編集:実際の問題(ある種の不変量が与えられた点の近くのクラスター)は、平均的な場合、O(n ^ 2)よりもうまく解決できるはずですが、私の問題定義には重大な欠陥があります:=〜は同値関係ではありません単純な事実のため、推移的なプロパティを尊重しません。これが、この問題を解決するのが簡単ではなく、高度な技術が必要な主な理由だと思います。私の実際の解決策をすぐに投稿します:近くの点がすべて定義された=〜を満たすときに機能するはずです。極が離れている点が関係を尊重しないが、それらがクラスター化された点の重心と関係している場合、失敗する可能性があります。それは私の入力データスペースでうまく機能しますが、あなたの入力データスペースではうまくいかないかもしれません。誰かがこの問題の完全な正式な特徴を知っていますか(解決策付き)?

4

5 に答える 5

1

問題を言い換える1つの方法は、次のとおりですn。2Dポイントのセットが与えられた場合、各ポイントについて、を中心とするp直径の円に含まれるポイントのセットを見つけます。deltap

素朴な線形探索は、O(n^2)あなたがほのめかしているアルゴリズムを提供します。

最悪の場合、これが最善の方法であるように思われます。セット内のすべてのポイントが直径<=の円内に含まれている場合delta、各nクエリはO(n)ポイントを返す必要があり、O(n^2)全体的に複雑になります。

ただし、より合理的なデータセットでより良い結果が得られるはずです。これ(特にスペース分割に関するセクション)とKDツリーを見てください。後者はO(n^2)、妥当な場合にサブアルゴリズムを提供するはずです。

問題を見る別の方法があるかもしれません。それはより複雑なものを与えるでしょう。頭のてっぺんから何も思いつかない。

于 2010-12-05T23:10:52.127 に答える
0

これは、「デルタ内の点Pのすべての近傍を検索する」を解決する必要があるC#KdTree実装です。関数型プログラミング技術を多用します(はい、私はPythonが大好きです)。それはテストされていますが、私はまだ理解に疑問があります。「平均的な場合、O(n ^ 2)よりも良い〜=関係が与えられたn点の集合を分割する」という問題を解決するためのコード(または擬似コード)は、別の回答に掲載されています。_TreeFindNearest()

/*
Stripped C# 2.0 port of ``kdtree'', a library for working with kd-trees.
Copyright (C) 2007-2009 John Tsiombikas <nuclear@siggraph.org>
Copyright (C) 2010 Francesco Pretto <ceztko@gmail.com>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

using System;
using System.Collections.Generic;
using System.Text;

namespace ITR.Data.NET
{
    public class KdTree<T>
    {
        #region Fields

        private Node _Root;
        private int _Count;
        private int _Dimension;
        private CoordinateGetter<T>[] _GetCoordinate;

        #endregion // Fields

        #region Constructors

        public KdTree(params CoordinateGetter<T>[] coordinateGetters)
        {
            _Dimension = coordinateGetters.Length;
            _GetCoordinate = coordinateGetters;
        }

        #endregion // Constructors

        #region Public methods

        public void Insert(T location)
        {
            _TreeInsert(ref _Root, 0, location);
            _Count++;
        }

        public void InsertAll(IEnumerable<T> locations)
        {
            foreach (T location in locations)
                Insert(location);
        }

        public IEnumerable<T> FindNeighborsRange(T location, double range)
        {
            return _TreeFindNeighborsRange(_Root, 0, location, range);
        }

        #endregion // Public methods

        #region Tree traversal

        private void _TreeInsert(ref Node current, int currentPlane, T location)
        {
            if (current == null)
            {
                current = new Node(location);
                return;
            }

            int nextPlane = (currentPlane + 1) % _Dimension;

            if (_GetCoordinate[currentPlane](location) <
                    _GetCoordinate[currentPlane](current.Location))
                _TreeInsert(ref current._Left, nextPlane, location);
            else
                _TreeInsert(ref current._Right, nextPlane, location);
        }

        private IEnumerable<T> _TreeFindNeighborsRange(Node current, int currentPlane,
            T referenceLocation, double range)
        {
            if (current == null)
                yield break;

            double squaredDistance = 0;
            for (int it = 0; it < _Dimension; it++)
            {
                double referenceCoordinate = _GetCoordinate[it](referenceLocation);
                double currentCoordinate = _GetCoordinate[it](current.Location);
                squaredDistance +=
                    (referenceCoordinate - currentCoordinate)
                    * (referenceCoordinate - currentCoordinate);
            }

            if (squaredDistance <= range * range)
                yield return current.Location;

            double coordinateRelativeDistance =
                _GetCoordinate[currentPlane](referenceLocation)
                    - _GetCoordinate[currentPlane](current.Location);
            Direction nextDirection = coordinateRelativeDistance <= 0.0
                ? Direction.LEFT : Direction.RIGHT;
            int nextPlane = (currentPlane + 1) % _Dimension;
            IEnumerable<T> subTreeNeighbors =
                _TreeFindNeighborsRange(current[nextDirection], nextPlane,
                    referenceLocation, range);
            foreach (T location in subTreeNeighbors)
                yield return location;

            if (Math.Abs(coordinateRelativeDistance) <= range)
            {
                subTreeNeighbors =
                    _TreeFindNeighborsRange(current.GetOtherChild(nextDirection),
                        nextPlane, referenceLocation, range);
                foreach (T location in subTreeNeighbors)
                    yield return location;
            }
        }

        #endregion // Tree traversal

        #region Node class

        public class Node
        {
            #region Fields

            private T _Location;
            internal Node _Left;
            internal Node _Right;

            #endregion // Fields

            #region Constructors

            internal Node(T nodeValue)
            {
                _Location = nodeValue;
                _Left = null;
                _Right = null;
            }

            #endregion // Contructors

            #region Children Indexers

            public Node this[Direction direction]
            {
                get { return direction == Direction.LEFT ? _Left : Right; }
            }

            public Node GetOtherChild(Direction direction)
            {
                return direction == Direction.LEFT ? _Right : _Left;
            }

            #endregion // Children Indexers

            #region Properties

            public T Location
            {
                get { return _Location; }
            }

            public Node Left
            {
                get { return _Left; }
            }

            public Node Right
            {
                get { return _Right; }
            }

            #endregion // Properties
        }

        #endregion // Node class

        #region Properties

        public int Count
        {
            get { return _Count; }
            set { _Count = value; }
        }

        public Node Root
        {
            get { return _Root; }
            set { _Root = value; }
        }

        #endregion // Properties
    }

    #region Enums, delegates

    public enum Direction
    {
        LEFT = 0,
        RIGHT
    }

    public delegate double CoordinateGetter<T>(T location);

    #endregion // Enums, delegates
}
于 2010-12-07T17:21:59.470 に答える
0

Quadtreeにとって間違いなく問題です。

また、各座標で並べ替えて、これら2つのリストで遊んでみることができます(並べ替えはn*log(n)、を満たすポイントのみを確認できdx <= delta && dy <= deltaます。また、2つのレベルのポインターを含む並べ替えられたリストに入れることもできます。1つはOXでの解析用で、もう1つはOXでの解析用です。 OYのためのもう一つ。

于 2010-12-05T22:58:05.710 に答える
0

各点について、原点からの距離D(n)を計算します。これは、O(n)演算です。

O(n ^ 2)アルゴリズムを使用して、D(ab)<deltaである一致を検索し、D(a)-D(b)>deltaをスキップします。

(できれば大きい)数がスキップされるため、結果は平均してO(n ^ 2)よりも優れている必要があります。

于 2010-12-07T12:12:37.760 に答える
0

次のC#メソッドは、KdTreeクラス、Join()(引数として渡されたすべてのコレクションを列挙)およびShuffled()(渡されたコレクションのシャッフルされたバージョンを返す)メソッドとともに、私の質問の問題を解決します。私の問題で行っているように、referenceVectorsがと同じベクトルである場合、いくつかの欠陥のあるケース(質問のEDITを読んでください)があるかもしれません。vectorsToRelocate

public static Dictionary<Vector2D, Vector2D> FindRelocationMap(
    IEnumerable<Vector2D> referenceVectors,
    IEnumerable<Vector2D> vectorsToRelocate)
{
    Dictionary<Vector2D, Vector2D> ret = new Dictionary<Vector2D, Vector2D>();

    // Preliminary filling
    IEnumerable<Vector2D> allVectors =
        Utils.Join(referenceVectors, vectorsToRelocate);
    foreach (Vector2D vector in allVectors)
        ret[vector] = vector;

    KdTree<Vector2D> kdTree = new KdTree<Vector2D>(
        delegate(Vector2D vector) { return vector.X; },
        delegate(Vector2D vector) { return vector.Y; });
    kdTree.InsertAll(Utils.Shuffled(ret.Keys));

    HashSet<Vector2D> relocatedVectors = new HashSet<Vector2D>();
    foreach (Vector2D vector in referenceVectors)
    {
        if (relocatedVectors.Contains(vector))
            continue;

        relocatedVectors.Add(vector);

        IEnumerable<Vector2D> neighbors =
            kdTree.FindNeighborsRange(vector, Tolerances.EUCLID_DIST_TOLERANCE);

        foreach (Vector2D neighbor in neighbors)
        {
            ret[neighbor] = vector;
            relocatedVectors.Add(neighbor);
        }
    }

    return ret;
}
于 2010-12-09T22:33:35.757 に答える