Contare le disposizioni di recinzione massime


9

sfondo

Voglio costruire una recinzione. Per questo, ho raccolto un mucchio di pali e li ho bloccati a terra. Ho anche raccolto un sacco di assi che inchioderò ai pali per realizzare il recinto reale. Tendo a lasciarmi trasportare dalle cose, e molto probabilmente continuerò a inchiodare le assi ai pali fino a quando non c'è più posto dove metterle. Voglio che tu enumeri le possibili recinzioni con cui posso finire.

Ingresso

Il tuo input è un elenco di coordinate intere bidimensionali che rappresentano le posizioni dei poli, in qualsiasi formato conveniente. Puoi presumere che non contenga duplicati, ma non puoi assumere nulla del suo ordine.

Le schede sono rappresentate da linee rette tra i poli e, per semplicità, consideriamo solo schede orizzontali e verticali. Due assi possono essere uniti da una tavola se non ci sono altri poli o assi tra loro, il che significa che le assi non possono incrociarsi. Una disposizione di poli e pannelli è massima se non è possibile aggiungere nuovi pannelli (equivalentemente, c'è un palo o un pannello tra due poli allineati orizzontalmente o verticalmente).

Produzione

Il tuo output è il numero di disposizioni massime che possono essere costruite usando i poli.

Esempio

Considera l'elenco di input

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

Vista dall'alto, la disposizione dei poli corrispondente assomiglia a questa:

  o
 o o
o    o
 o o
  o

Esistono esattamente tre disposizioni massime che possono essere costruite usando questi poli:

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

Quindi l'output corretto è 3.

Regole

È possibile scrivere una funzione o un programma completo. Vince il conteggio di byte più basso e non sono consentite scappatoie standard.

Casi 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

1
L'esempio sembra avere (-2,0) due volte. Uno di questi dovrebbe essere (2,0)?
Isaacg,

@isaacg In realtà, dovrebbe essere (0,-2), buona cattura. Cambiando adesso.
Zgarb,

Risposte:


5

Mathematica, 301 byte

(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}]])&

Questa è una funzione senza nome che accetta le coordinate come nidificate Liste restituisce un numero intero. Cioè, puoi dargli un nome e chiamarlo, o semplicemente aggiungere

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

Con rientro:

(
  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}
    ]
  ]
) &

Non posso nemmeno iniziare a esprimere quanto sia ingenua questa implementazione ... sicuramente non potrebbe essere più forza bruta ...

  • Ottieni tutte le coppie (non ordinate) di poli.
  • Ordina ogni coppia e tutte le coppie in un ordine canonico.
  • Elimina le coppie che non condividono una coordinata (ovvero che non sono collegabili da una linea ortogonale).
  • Le coppie di scarti possono essere formate da due coppie più brevi (in modo da o--o--oprodurre solo due recinzioni anziché tre).
  • Ottieni tutti i sottoinsiemi di quelle coppie, ovvero tutte le possibili combinazioni di recinzioni.
  • Filtra le combinazioni che hanno recinzioni che si incrociano.
  • Contare il numero di set di recinti risultanti per i quali non è possibile trovare alcun superset rigoroso nell'elenco.

Sorprendentemente, risolve praticamente immediatamente tutti i casi di test.

Un trucco davvero accurato che ho scoperto per questo è l'uso di Orderlessridurre il numero di modelli che devo abbinare. In sostanza, quando voglio abbandonare i set di recinzioni con recinzioni incrociate, devo trovare un paio di recinzioni verticali e orizzontali e verificarne le condizioni. Ma non so in quale ordine appariranno. Dato che i modelli di elenco dipendono normalmente dall'ordine, ciò comporterebbe due modelli molto lunghi. Quindi invece rimpiazzo con l'elenco circostante con una funzione tcon t @@@- che non è definita, quindi viene mantenuta così com'è. Ma quella funzione è Orderless, quindi posso solo controllare un singolo ordine nel modello e Mathematica lo verificherà contro tutte le permutazioni. Successivamente, rimetto a posto le liste con List @@@.

Vorrei che ci fosse un built-in che è a) Orderless, b) not Listable ec) non definito per 0 argomenti o argomenti elenco. Allora potrei sostituirlo tcon quello. Ma non sembra esserci un tale operatore.


Quando stai pensando se Mathematica lo fa nel modo giusto o abbastanza veloce, la risposta è "sì".
Seequ,

Bene, è ingenuo quanto la mia implementazione di riferimento. : P
Zgarb,

1

Haskell, 318 byte

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]

Uso: p [(1,0),(0,1),(-1,0),(0,-1)]. Produzione:2

Come funziona:

  • crea tutti gli elenchi secondari dell'elenco di input e mantieni quelli con due elementi e con coordinate x uguali o y uguali. Questo è un elenco di tutte le coppie di poli in cui è possibile costruire una recinzione in mezzo.
  • crearne tutte le liste
  • aggiungere schede per ogni elenco
  • rimuove gli elenchi in cui una coordinata xy appare due volte (schede e poli)
  • rimuovere elenchi duplicati (solo schede) per gestire più elenchi vuoti, a causa di poli direttamente adiacenti (ad es. (1,0) e (1,1))
  • mantenere quelli che non sono un sottoelenco rigoroso di un altro elenco
  • contare le liste rimanenti
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.