Compter les dispositions de clôture maximales

9

Contexte

Je veux construire une clôture. Pour cela, j'ai rassemblé un tas de poteaux et les ai collés au sol. J'ai également rassemblé beaucoup de planches que je clouerai aux poteaux pour faire la clôture réelle. J'ai tendance à m'emporter lors de la construction de trucs, et je vais probablement continuer à clouer les planches aux poteaux jusqu'à ce qu'il n'y ait plus de place pour les mettre. Je veux que vous énumériez les clôtures possibles avec lesquelles je peux me retrouver.

Contribution

Votre entrée est une liste de coordonnées entières bidimensionnelles représentant les positions des pôles, dans n'importe quel format pratique. Vous pouvez supposer qu'il ne contient aucun doublon, mais vous ne pouvez rien supposer de son ordre.

Les planches sont représentées par des lignes droites entre les pôles, et pour simplifier, nous ne considérons que les planches horizontales et verticales. Deux poteaux peuvent être joints par une planche s'il n'y a pas d'autres poteaux ou planches entre eux, ce qui signifie que les planches ne peuvent pas se croiser. Un arrangement de poteaux et de panneaux est maximal si aucun nouveau panneau ne peut y être ajouté (de manière équivalente, il y a un poteau ou un panneau entre deux poteaux alignés horizontalement ou verticalement).

Production

Votre sortie est le nombre d'arrangements maximaux qui peuvent être construits à l'aide des pôles.

Exemple

Considérez la liste d'entrée

[(3,0),(1,1),(0,2),(-1,1),(-2,0),(-1,-1),(0,-2),(1,-1)]

Vu de dessus, l'agencement correspondant des poteaux ressemble à ceci:

  o
 o o
o    o
 o o
  o

Il existe exactement trois dispositions maximales qui peuvent être construites à l'aide de ces pôles:

  o        o        o
 o-o      o|o      o-o
o----o   o||| o   o| | o
 o-o      o|o      o-o
  o        o        o

Ainsi, la sortie correcte est 3.

Règles

Vous pouvez écrire soit une fonction soit un programme complet. Le nombre d'octets le plus bas l'emporte et les failles standard sont interdites.

Cas de test

[] -> 1
[(0,0),(1,1),(2,2)] -> 1
[(0,0),(1,0),(2,0)] -> 1
[(0,0),(0,1),(1,0),(1,1)] -> 1
[(1,0),(0,1),(-1,0),(0,-1)] -> 2
[(3,0),(1,1),(0,2),(-1,1),(-2,0),(-1,-1),(0,-2),(1,-1)] -> 3
[(0,0),(4,0),(1,1),(1,-2),(3,1),(3,-2),(2,-1),(4,-1)] -> 3
[(0,0),(4,0),(1,1),(1,-2),(3,1),(3,-2),(2,-1),(4,-1),(0,-1)] -> 4
[(0,0),(4,0),(1,1),(1,-2),(3,1),(3,-2),(2,-1),(0,-1),(2,2)] -> 5
[(0,0),(4,0),(1,1),(1,-2),(3,1),(3,-2),(2,-1),(4,-1),(0,-1),(2,2)] -> 8
Zgarb
la source
1
L'exemple semble avoir (-2,0) deux fois. Un de ceux-ci devrait-il être (2,0)?
isaacg
@isaacg En fait, ça devrait être une (0,-2)bonne prise. En train de changer maintenant.
Zgarb

Réponses:

5

Mathematica, 301 octets

(t~SetAttributes~Orderless;u=Subsets;c=Complement;l=Select;f=FreeQ;Count[s=List@@@l[t@@@u[Sort@l[Sort/@#~u~{2},!f[#-#2&@@#,0]&]//.{a___,{x_,y_},{x_,z_},b___,{y_,z_},c___}:>{a,{x,y},b,{y,z},c}],f[#,t[{{a_,b_},{a_,c_}},{{d_,e_},{f_,e_}},___]/;d<a<f&&b<e<c]&],l_/;f[s,k_List/;k~c~l!={}&&l~c~k=={},{1}]])&

Il s'agit d'une fonction sans nom qui prend les coordonnées comme imbriquées Listet renvoie un entier. Autrement dit, vous pouvez soit lui donner un nom et l'appeler, ou simplement ajouter

@ {{3, 0}, {1, 1}, {0, 2}, {-1, 1}, {-2, 0}, {-1, -1}, {0, -2}, {1, -1}}

Avec retrait:

(
  t~SetAttributes~Orderless;
  u = Subsets;
  c = Complement;
  l = Select;
  f = FreeQ;
  Count[
    s = List @@@ l[
      t @@@ u[
        Sort @ l[
          Sort /@ #~u~{2}, 
          !f[# - #2 & @@ #, 0] &
        ] //. {a___, {x_, y_}, {x_, z_}, b___, {y_, z_}, c___} :> 
              {a, {x, y}, b, {y, z}, c}
      ],
      f[
        #,
        t[{{a_, b_}, {a_, c_}}, {{d_, e_}, {f_, e_}}, ___] 
          /; d < a < f && b < e < c
      ] &
    ], 
    l_ /; f[
      s, 
      k_List /; k~c~l != {} && l~c~k == {}, 
      {1}
    ]
  ]
) &

Je ne peux même pas commencer à exprimer à quel point cette implémentation est naïve ... elle ne pourrait certainement pas être plus brutale ...

  • Obtenez toutes les paires de pôles (non ordonnées).
  • Triez chaque paire et toutes les paires dans un ordre canonique.
  • Jeter les paires qui ne partagent pas une coordonnée (c'est-à-dire qui ne sont pas connectables par une ligne orthogonale).
  • Les paires de défausse peuvent être formées de deux paires plus courtes (ce qui o--o--one donne que deux clôtures au lieu de trois).
  • Obtenez tous les sous-ensembles de ces paires, c'est-à-dire toutes les combinaisons possibles de clôtures.
  • Filtrez les combinaisons dont les clôtures se croisent.
  • Comptez le nombre d'ensembles de clôtures résultants pour lesquels aucun surensemble strict ne peut être trouvé dans la liste.

Étonnamment, il résout tous les cas de test presque immédiatement.

Une astuce vraiment intéressante que j'ai découverte pour cela est l'utilisation de Orderlesspour réduire le nombre de motifs que je dois faire correspondre. Essentiellement, lorsque je veux abandonner des ensembles de clôtures avec des clôtures croisées, je dois trouver une paire de clôture verticale et horizontale et vérifier leur état. Mais je ne sais pas dans quel ordre ils apparaîtront. Comme les modèles de liste dépendent normalement de l'ordre, cela entraînerait deux modèles très longs. Donc, au lieu de cela, je remplace par la liste environnante par une fonction tavec t @@@- qui n'est pas définie de sorte qu'elle est maintenue telle quelle. Mais cette fonction est Orderless, donc je peux juste vérifier un seul ordre dans le motif, et Mathematica le vérifiera par rapport à toutes les permutations. Ensuite, j'ai remis les listes en place avec List @@@.

Je souhaite qu'il y ait un intégré qui est a) Orderless, b) pas Listable et c) non défini pour 0 arguments ou arguments de liste. Ensuite, je pourrais remplacer tpar cela. Mais il ne semble pas y avoir un tel opérateur.

Martin Ender
la source
Lorsque vous pensez que Mathematica le fait correctement ou assez rapidement, la réponse est "oui".
seequ
Eh bien, c'est à peu près aussi naïf que mon implémentation de référence. : P
Zgarb
1

Haskell, 318 octets

import Data.List
s=subsequences
k[(_,a,b),(_,c,d)]|a==c=f(\w->(1,a,w))b d|1<2=f(\w->(2,w,b))a c
f t u v=[t x|x<-[min u v+1..max u v-1]]
q l=nub[x|x<-map(k=<<)$s[a|a@[(_,n,m),(_,o,p)]<-s l,n==o||m==p],x++l==nubBy(\(_,a,b)(_,c,d)->a==c&&b==d)(x++l)]
m=q.map(\(a,b)->(0,a,b))
p l=sum[1|x<-m l,all(\y->y==x||x\\y/=[])$m l]

Utilisation: p [(1,0),(0,1),(-1,0),(0,-1)]. Production:2

Comment ça fonctionne:

  • créer toutes les sous-listes de la liste d'entrée et conserver celles avec deux éléments et avec des coordonnées x ou y égales. Ceci est une liste de toutes les paires de poteaux où une clôture peut être construite entre les deux.
  • en créer toutes les sous-listes
  • ajouter des tableaux pour chaque liste
  • supprimer les listes où une coordonnée xy apparaît deux fois (planches et poteaux)
  • supprimer les listes en double (cartes uniquement) pour gérer plusieurs listes vides, en raison des pôles directement adjacents (par exemple (1,0) et (1,1))
  • conserver ceux qui ne sont pas une sous-liste stricte d'une autre liste
  • compter les listes restantes
nimi
la source