8
votes

Création d'ensembles d'éléments similaires dans un tableau 2D

J'essaie de résoudre un problème basé sur un tableau 2D. Ce tableau contient différents types d'éléments (à partir d'un total de 3 types possibles). Permet d'assumer le type comme x x, y, z.

le tableau semble être quelque chose comme ça. Notez qu'il serait toujours complètement rempli. Le diagramme est pour l'illustration. P>

7 | | | | | | |
6 | | | | | | |
5 | | | | | | |
4 | |X|Z|Y|X| |
3 | |Y|X|Y|Y|X|
2 |Y|Y|X|Z|Z|X|
1 |X|X|Y| |X|X|
0 | | | |Z| | |
   0 1 2 3 4 5


6 commentaires

Cet article Wikipedia parle d'algorithmes efficaces pour "Track dynamiquement [ING]. Les composants d'un graphique sous forme de sommets et de bords sont ajoutés [ou supprimés] ". Les algorithmes réels semblent toutefois provenir d'une publication imprimée uniquement.


Quelle est la taille des matrices que vous aimez?


@Davideisenstat 6 x 8


Vous devriez itérer des colonnes sur des lignes; Pour chacun si la cellule n'est pas visitée, appelez la fonction récursive qui remplit les composants connectés dans la matrice.


Quelle vitesse minimale serait acceptable pour chaque réseau d'itération / ré-itération?


Je viens de remarquer que les tableaux ne sont que 6x8! Dans ce cas, vous pouvez simplement utiliser la structure de données union / trouvaille la plus simple possible, ne vous inquiétez pas avec la compression de chemin ni la tailles de sous-arbitre ni quoi que ce soit comme ça. En fait, vous pourriez oublier les arbres tout à fait et utilisez simplement un tableau uni pour les étiquettes et faire union () vérifier et mettre à jour jusqu'à tous les éléments de chaque appel - cela sera toujours ridiculement rapide.


4 Réponses :


1
votes

Dans votre situation, je vous fierais au moins sur deux tableaux différents:

private bool isSurroundingPoint(Point point1, Point point2)
{
    bool isSurrounding = false;
    if (point1.X == point2.X || point1.X == point2.X + 1 || point1.X == point2.X - 1)
    {
        if (point1.Y == point2.Y || point1.Y == point2.Y + 1 || point1.Y == point2.Y - 1)
        {
            isSurrounding = true;
        }
    }
    return isSurrounding;
}


0 commentaires

7
votes

[modifier le 5/8/2013: complexité du temps fixe. (O (A (n)) est essentiellement une période constante!)]

Dans ce qui suit, par "composant connecté", je veux dire l'ensemble de toutes les positions accessibles par un chemin qui ne permet que des déplacements horizontaux, verticaux ou diagonaux entre les positions voisines ayant le même type d'élément. Par exemple. Votre exemple {(0,1), (1,1), (2,2), (2,3), (1,4)} est un composant connecté dans votre exemple d'entrée. Chaque position appartient exactement à un composant connecté.

Nous construirons un Structure de données Union / Recherche qui sera utilisée pour donner chaque Position (x, Y) une "étiquette" numérique ayant la propriété que si et seulement si deux positions (x, y) et (x, y ') appartiennent au même composant alors ils ont la même étiquette. En particulier, cette structure de données prend en charge trois opérations:

  • SET (x, y, i) définira l'étiquette de position (x, y) vers i.
  • Recherche (x, y) retournera l'étiquette attribuée à la position (x, y).
  • Union (z) , pour certains étiquettes Z, combinera toutes les étiquettes de Z dans une seule étiquette K, dans le sens des appels futurs vers Rechercher (x, Y) sur n'importe quelle position (x, y) qui avait précédemment eu une étiquette dans Z renverra maintenant k. (En général, K sera l'une des étiquettes déjà dans Z, bien que cela ne soit pas vraiment important.) Union (z) renvoie également la nouvelle étiquette "maître", k.

    S'il y a n = la largeur * Positions de hauteur au total, cela peut être effectué dans O (N * A (N)), où A () est la fonction d'Ackermann inverse extrêmement lente. pour toutes les tailles d'entrée pratiques, c'est la même chose que O (n).

    Notez que chaque fois que deux sommets sont adjacents les uns aux autres, il y a quatre cas possibles:

    1. L'un est au-dessus de l'autre (relié par un bord vertical)
    2. l'un est à gauche de l'autre (relié par un bord horizontal)
    3. L'un est au-dessus et à gauche de l'autre (connecté par un \ bord diagonal)
    4. L'un est au-dessus et à droite de l'autre (connecté par un / bord diagonal)

      Nous pouvons utiliser la passe suivante pour déterminer les étiquettes pour chaque position (x, y):

      • Ensemble NextLabel à 0.
      • pour chaque rangée y dans l'ordre croissant:
        • pour chaque colonne x dans l'ordre croissant:
          • examinez les voisins W, NW, N et NE de (x, y). Soit Z le sous-ensemble de ces 4 voisins qui sont de même nature que (x, y).
          • Si z est l'ensemble vide, nous supposons que nous supposons provisoirement que (x, y) démarre un nouveau composant, donc appelé (X, Y, NextLabel) et Incrément NextLabel.
          • Sinon, appelez (z [i]) sur chaque élément de Z pour trouver leurs étiquettes et appelez Union () sur cet ensemble d'étiquettes pour les combiner ensemble. Attribuez la nouvelle étiquette (le résultat de cet appel de l'Union ()) à K, puis d'appeler également défini (x, y, k) pour ajouter (x, y) à ce composant.

            Après cela, appeler trouver (x, y) sur n'importe quelle position (x, y) vous indique efficacement quel composant il appartient. Si vous souhaitez être capable de répondre rapidement à des requêtes du formulaire "Quels positions appartiennent au composant connecté contenant position (x, y)?" Ensuite, créez une haquetable de listes postincomp et créez une deuxième passe sur le tableau d'entrée, ajoute chacun (x, y) à la liste postincomp [Rechercher (x, y)] . Cela peut tous être fait en temps et à l'espace linéaire. Maintenant, pour répondre à une requête pour une position donnée (x, y), appelez simplement lab = rechercher (x, y) pour trouver l'étiquette de cette position, puis répertoriez les positions dans Posincomp [Lab ] .

            Pour faire face à des composants "trop ​​petits", il suffit de regarder la taille de postincomp [laboratoire] . Si c'est 1 ou 2, alors (x, y) n'appartient à aucun composant "assez gros".

            Enfin, tout ce travail prend effectivement du temps linéaire, il sera donc rapide que votre matrice d'entrée soit énorme. Il est donc parfaitement raisonnable de la recomposer à partir de zéro après la modification du tableau d'entrée.


0 commentaires

1
votes

Vous voudrez peut-être consulter Rel="nofewe"> Région en croissance algorithmes, utilisée pour la segmentation d'image. Ces algorithmes commencent par un pixel de semences et cultivent une région contiguë où tous les pixels de la région ont des biens.

Dans votre cas, les "pixels" adjacents sont dans le même segment d'image si elles ont la même étiquette (c'est-à-dire, type d'élément x, y ou z)


0 commentaires

0
votes

J'ai écrit Quelque chose pour trouver des objets d'un seul type pour un autre afin question. L'exemple ci-dessous ajoute deux autres types. Toute ré-itération examinerait à nouveau toute la liste. L'idée est de traiter la liste des points pour chaque type séparément. La fonction résoudre code> Groupes tous les points connectés et les supprime de la liste avant d'énumérer le groupe suivant. Areconnected CODE> Vérifie la relation entre les coordonnées des points "puisque nous ne testons que des points d'un type. Dans cette version généralisée, les types ( ABC code>) peuvent être n'importe quoi (chaînes, chiffres, tuples, etc.), tant qu'ils correspondent.

BTW - Voici un lien vers un exemple javascript de J_RANDOM_Hacker's TerifIFIC Algorithm: http://jsfiddle.net/groovy/fp5kp/ p> Code HASKELL: P>

*Main> objects 'x' 'y' 'z' example
[("X",[[(7,0),(6,0),(5,0),(4,0)]
      ,[(3,4),(5,2),(5,3),(4,3),(2,2),(3,2),(2,1),(0,1),(1,0),(0,0)]])
,("Y",[[(7,5),(6,4),(7,4),(6,3)],[(4,4),(4,5),(3,5),(2,5)]
      ,[(4,1),(3,0),(3,1),(0,4),(2,0),(0,3),(1,1),(1,2),(0,2)]])
,("Z",[[(5,5),(6,5),(5,4)]
      ,[(7,2),(6,2),(5,1),(4,2),(3,3),(1,3),(2,3),(2,4),(1,4),(1,5),(0,5)]])]
(0.02 secs, 1560072 bytes)


0 commentaires