Cerchi che dividono l'aereo


23

Compito

Ti verrà dato un set di cerchi nel piano con i loro centri sulla linea y = 0 . È garantito che nessuna coppia di cerchi ha più di un punto comune.

Il tuo compito è determinare in quante regioni in cui i cerchi dividono il piano. Una regione è un insieme contiguo di punti inclusione-massima che non interseca nessuno dei cerchi.

Dovresti scrivere un programma che calcola questa risposta quando ti viene data una descrizione dei cerchi.


Ecco un esempio:

Esempio 1

Sul lato sinistro puoi vedere i cerchi disegnati sul piano. Tuttavia, nella metà destra dell'immagine, le regioni prodotte dai cerchi sono colorate distintamente (un colore per regione). Ci sono sei regioni in questo esempio.


Ingresso

La prima riga dell'input contiene un numero N, il numero di descrizioni dei cerchi da seguire. Questa linea è facoltativa, se la tua soluzione funziona senza di essa, va bene.

Le seguenti Nlinee ciascuna contengono due numeri interi, x i e r i > 0 , che rappresenta un cerchio con centro (x i , 0) e raggio r i .

È garantito che nessuna coppia di cerchi ha più di un punto comune. Si è ulteriormente garantito che x i e r io non supero 10^9in valore assoluto (in modo da adattarsi comodamente in un intero a 32 bit).


L'input può essere:

  • letto da STDIN

  • letto da un file chiamato Inella directory corrente

In alternativa, l'input potrebbe essere:

  • disponibile come stringa (comprese le nuove righe) in una variabile globale

  • sullo stack


Produzione

Questo dovrebbe essere un singolo numero intero, il numero per le regioni prodotte. Questo dovrebbe essere scritto su STDOUT o su un file chiamato Onella directory corrente.


Regole

  • Vince il codice più breve in byte

  • +200 byte di penalità se il codice non ha un polinomio di runtime + spazio in n

  • Bonus di -100 byte per runtime previsto nel caso peggiore + complessità dello spazio O(n log n)

  • Bonus di -50 byte per runtime previsto nel caso peggiore + complessità dello spazio O(n)

  • Bonus di -100 byte per runtime deterministico + complessità dello spazio O(n)

Durante la valutazione del runtime:

  • Supponiamo che le tabelle hash abbiano O(1)previsto il runtime per l'inserimento, l'eliminazione e la ricerca, indipendentemente dalla sequenza di operazioni e dai dati di input. Ciò può essere vero o no, a seconda che l'implementazione utilizzi la randomizzazione.

  • Supponiamo che il tipo incorporato del tuo linguaggio di programmazione richieda O(n log n)tempo deterministico , dov'è nla dimensione della sequenza di input.

  • Supponiamo che le operazioni aritmetiche sui numeri di input richiedano solo O(1)tempo.

  • Non dare per scontato che i numeri di input siano vincolati da una costante, sebbene, per ragioni pratiche, lo siano. Ciò significa che algoritmi come il radix sort o il counting sort non sono tempi lineari. In generale, dovrebbero essere evitati fattori costanti molto grandi.


Esempi

Ingresso:

2 
1 3
5 1

Produzione: 3


Ingresso:

3
2 2
1 1
3 1

Produzione: 5

4
7 5
-9 11
11 9
0 20

Ingresso:

9
38 14
-60 40
73 19
0 100
98 2
-15 5
39 15
-38 62
94 2

Produzione: 11


suggerimenti

Possiamo usare la seguente idea per una soluzione molto compatta. Consente di intersecare l'insieme di cerchi con l'asse X e interpretare i punti di intersezione come nodi in un grafico planare:

inserisci qui la descrizione dell'immagine

Ogni cerchio produce esattamente 2 bordi in questo grafico e fino a due nodi. Possiamo contare il numero di nodi usando una tabella hash per tenere traccia del numero totale di bordi distinti a sinistra o a destra.

Quindi possiamo usare la formula caratteristica di Eulero per calcolare il numero di facce di un disegno del grafico:

V - E + F - C = 1

F = E - V + C + 1

Per calcolare Cil numero di componenti collegati, possiamo usare una ricerca approfondita .


Nota: questa idea del problema è presa in prestito da un recente concorso di programmazione croato , ma per favore non imbrogliare guardando i contorni della soluzione. :)


Alcuni di questi bonus sono esche?
user2357112 supporta Monica

@ user2357112 Non dare per scontato che non possa essere fatto a meno che tu non possa provarlo;)
Niklas B.

Bene, con gli input garantiti per adattarsi a un intero macchina, potremmo usare un ordinamento radix e chiamarlo O (n). Odio assumere dimensioni di input limitate, perché in senso stretto, significa che ci sono finitamente molti input possibili.
user2357112 supporta Monica

@ user2357112 No, ho detto che non puoi supporre che gli interi siano delimitati durante la valutazione degli asintotici, quindi né l'ordinamento radix né l'ordinamento conteggio sarebbero tempo e spazio lineari. Che si adattino a una parola è solo per rendere l'aritmetica "reale" O (1) e per ragioni pratiche (larghezza variabile limitata nella maggior parte delle lingue)
Niklas B.

@NiklasB. se ho un algoritmo in cui l'unico componente con complessità superlineare è l'ordinamento, devo implementare l'ordinamento unificato se il mio linguaggio utilizza l'ordinamento rapido, al fine di ottenere il n log nbonus? Inoltre, ho una nuova soluzione concettualmente nuova. Devo pubblicare una nuova risposta per sostituire quella precedente? (Preferirei la prima, nel caso in cui la mia nuova soluzione non fosse effettivamente corretta)
Martin Ender il

Risposte:


2

Mathematica, 125 122-150 = -28 caratteri

Non conosco la complessità della funzione integrata ConnectedComponents.

1+{-1,2,1}.Length/@{VertexList@#,EdgeList@#,ConnectedComponents@#}&@Graph[(+##)<->(#-#2)&@@@Rest@ImportString[#,"Table"]]&

Uso:

1+{-1,2,1}.Length/@{VertexList@#,EdgeList@#,ConnectedComponents@#}&@Graph[(+##)<->(#-#2)&@@@Rest@ImportString[#,"Table"]]&[
"9
38 14
-60 40
73 19
0 100
98 2
-15 5
39 15
-38 62
94 2"]

11


Penso che possiamo tranquillamente presumere che ConnectedComponentsabbia una complessità prevista nel caso peggiore, quindi se ci sono componenti O (n), questo andrebbe bene. Non capisco Mathematica, quindi non posso dire se è O (n) in generale e qualifica per il bonus -150? Penso di si. Lo eseguo semplicemente con input in STDIN?
Niklas B.

@NiklasB. il suo metodo di input sta semplicemente passando una variabile stringa a una funzione anonima. quindi penso che dovrebbe qualificarsi. per quanto riguarda l'output, in Mathematica questo comporterà semplicemente il numero che finirà nell'output della console, quindi anche questo dovrebbe andare bene.
Martin Ender,

Ho verificato la correttezza di questo, quindi penso che con un punteggio di -28 questo sia il nuovo leader. Congratulazioni!
Niklas B.

@NiklasB. perché solo 150? Quale parte dell'algoritmo presenta una complessità superlineare nel caso peggiore?
Martin Ender,

@ m.buettner 150 è per O (n) tempo previsto. Per i grafici con numeri arbitrari come nodi, definiti implicitamente come qui, non è possibile trovare il numero di CC in tempo lineare, che può essere mostrato riducendo la distinzione tra elementi e componenti collegati. Penso che possiamo anche ridurre la distinzione degli elementi rispetto al problema originale
Niklas B.

4

Rubino - 312 306 285 273 269 259 caratteri

Questa risposta è stata sostituita dal mio altro approccio che utilizza considerevolmente meno caratteri e corre O(n log n).

Ok andiamo. Per cominciare, volevo solo un'implementazione funzionante, quindi questo non è ancora ottimizzato algoritmicamente. Ordino i cerchi dal più grande al più piccolo e costruisco un albero (i cerchi inclusi in altri cerchi sono figli di quelli più grandi). Entrambe le operazioni prendono O(n^2)nel peggiore dei O(n log n)casi. Quindi eseguo l'iterazione attraverso l'albero per contare le aree. Se i bambini di un cerchio riempiono il suo intero diametro, ci sono due nuove aree, altrimenti ce n'è solo una. Questa iterazione prende O(n). Quindi ho una complessità generale O(n^2)e non mi qualifico né per ricompensa né penalità.

Questo codice prevede che l'input senza il numero di cerchi sia memorizzato in una variabile s:

t=[]
s.lines.map{|x|x,r=x.split.map &:to_i;{d:2*r,l:x-r,c:[]}}.sort_by!{|c|-c[:d]}.map{|c|i=-1;n=t
while o=n[i+=1]
if 0>d=c[:l]-o[:l]
break
elsif o[:d]>d
n=o[:c]
i=-1
end
end
n[i,0]=c}
a=1
t.map &(b=->n{d=0
n[:c].each{|c|d+=c[:d]}.map &b
a+=d==n[:d]?2:1})
p a

Versione non golfata (prevede input in variabile string):

list = []
string.split("\n").map { |x|
  m = x.split
  x,radius = m.map &:to_i
  list<<{x:x, d:2*radius, l:x-radius, r:x+radius, children:[]}
}
list.sort_by! { |circle| -circle[:d] }
tree = []
list.map { |circle|
  i = -1
  node = tree
  while c=node[i+=1]
    if circle[:x]<c[:l]
      break
    elsif circle[:x]<c[:r]
      node = c[:children]
      i = -1
    end
  end
  node[i,0] = circle
}
areas = 1
tree.map &(count = -> node {
  d = 0
  i = -1
  while c=node[:children][i+=1]
    count.call c
    d += c[:d]
  end
  areas += d == node[:d] ? 2 : 1
})
p areas

@NiklasB. sì, quel caso di prova sarebbe carino. La relazione che definisce i bordi nel mio albero è semplicemente l'inclusione di un cerchio in un altro. Dal momento che il cerchio non può essere contenuto in due cerchi che non si contengono (a causa della condizione "una intersezione"), non vedo come questo potrebbe essere un DAG.
Martin Ender,

I nipoti di un nodo sono anche i suoi figli?
user2357112 supporta Monica

@ user2357112 no, perché possono solo dividere il loro genitore diretto
Martin Ender il

@NiklasB. Se lo eseguo con l'esempio nella tua domanda, ottengo 11. Per quello nel tuo commento 9.
Martin Ender,

@NiklasB. aspetta, in realtà ottengo 10e 8con la mia versione non golfata, ma 11e 9con la mia attuale versione giocata a golf: D
Martin Ender

2

Rubino, 203 183 173 133-100 = 33 caratteri

Quindi ecco un approccio diverso. Questa volta, ordino i cerchi in base al punto più a sinistra. I cerchi che si toccano nel punto più a sinistra vengono ordinati dal più grande al più piccolo. Questo richiede O(n log n)(beh, Ruby usa l'ordinamento rapido, quindi in realtà l' O(n^2)implementazione dell'ordinamento merge / heap è probabilmente al di là dell'ambito di questa sfida). Quindi ripasso questa lista, ricordando tutte le posizioni più a sinistra e più a destra delle cerchie che ho visitato. Questo mi permette di rilevare se una serie di cerchi si collega completamente attraverso un cerchio più grande che lo circonda. In questo caso, ci sono due sottozone, altrimenti solo una. Questa iterazione richiede solo O(n)una complessità totale di O(n log n)cui si qualifica per la ricompensa di 100 caratteri.

Questo frammento prevede che l'input venga fornito tramite un file negli argomenti della riga di comando senza il numero di cerchi:

l,r={},{}
a=1
$<.map{|x|c,q=x.split.map &:to_r;[c-q,-2*q]}.sort.map{|x,y|a+=r[y=x-y]&&l[x]?2:1
l[y]=1 if l[x]&&!r[y]
l[x]=r[y]=1}
p a

Versione non golfata (prevede input in una variabile string):

list = []
string.split("\n").map { |x|
  m = x.split
  x,radius = m.map &:to_r
  list<<{x:x, d:2*radius, l:x-radius, r:x+radius}
}
list.sort_by! { |circle| circle[:l] + 1/circle[:d] }
l,r={},{}
areas = 1
list.map { |circle|
  x,y=circle[:l],circle[:r]
  if l[x] && r[y]
    areas += 2
  else
    areas += 1
    l[y]=1 if l[x]
  end
  r[y]=1
  l[x]=1
}
p areas

Sfortunatamente questo non funziona per tutti i test più grandi. È veloce però;) Questa volta non ho un piccolo esempio di errore, ma puoi trovare i dati del test sul sito web del concorso a cui ho collegato (è il concorso n. 6)
Niklas B.

Il primo testcase fallito è kruznice / kruznice.in.2, che è il primo caso di test "reale", quindi presumo che ci sia qualcosa di fondamentalmente sbagliato con l'algoritmo o l'implementazione. Funziona correttamente con cerchi arbitrariamente nidificati?
Niklas B.

@NiklasB. grazie, darò un'occhiata ai casi di test (potrei richiedere fino a domani sera per risolvere il problema)
Martin Ender,

@NiklasB. Ho capito il problema e la minima mancanza di esempio richiede 5 cerchi: -1 1 1 1 0 2 4 2 0 6. Penserò a come risolverlo entro domani sera (si spera).
Martin Ender,

L'analisi della complessità sembra presupporre che l'accesso alla matrice associativa sia un tempo costante. Ciò sembra improbabile che sia vero nel caso peggiore.
Peter Taylor,

1

Julia - 260-100 (bonus?) = 160

Interpretando i cerchi come figure con vertici (intersezioni), bordi e facce (aree del piano) possiamo relazionarci l'un l'altro usando la caratteristica di Eulero , quindi abbiamo solo bisogno di conoscere il numero di "vertici" e "spigoli" per avere il numero di "facce" o regioni del piano con la formula scritta sotto:Caratteristica di Eulero

AGGIORNAMENTO: Pensando un po 'ho capito che il problema con il mio metodo era solo quando i cerchi non erano collegati, quindi ho avuto un'idea, perché non collegarli artificialmente? Quindi il tutto soddisferà la formula di Eulero.

Esempio di cerchi

F = 2 + EV (V = 6, E = 9)

[Non lavorare con le cerchie nidificate, quindi non è una risposta al problema per i casi generali]

Codice :

s=readlines(open("s"))
n=int(s[1])
c=zeros(n,2)
t=[]
for i=1:n
    a=int(split(s[i+1]))
    c[i,1]=a[1]-a[2]
    c[i,2]=a[1]+a[2]
    if i==1 t=[c[1]]end
    append!(t,[c[i,1]:.5:c[i,2]])
end
e=0
t=sort(t)
for i in 1:(length(t)-1) e+=t[i+1]-t[i]>=1?1:0end #adds one edge for every gap
2+2n+e-length(unique(c)) # 2+E-V = 2+(2n+e)-#vertices

Penso che il tuo programma fallirà 2 -10 1 10 1.
Niklas B.

"È garantito che nessuna coppia di cerchi ha più di un punto comune". quindi penso che non si applicherà :)
CCP

@CCP Hanno zero punti comuni. n=2, i cerchi sono (C=(-10,0), r=1)e(C=(10,0), r=1)
Niklas B.

1
Il grafico non deve essere collegato per applicare la caratteristica di Eulero?
user2357112 supporta Monica

1
Ah, ecco un semplice caso: 4 0 2 1 1 10 2 11 1ma non credo di poterti dare molti più casi di test, sarebbe un po 'ingiusto
Niklas B.

1

Spidermonkey JS, 308, 287 , 273 - 100 = 173

Penso che se riscrivo questo in Ruby o Python potrei salvare i personaggi.

Codice:

for(a=[d=readline],e={},u=d(n=1);u--;)[r,q]=d().split(' '),l=r-q,r-=-q,e[l]=e[l]||[0,0],e[r]=e[r]||[0,0],e[r][1]++,e[l][0]++
for(k=Object.keys(e).sort(function(a,b)b-a);i=k.pop();a.length&&a.pop()&a.push(0)){for([l,r]=e[i];r--;)n+=a.pop()
for(n+=l;l--;)a.push(l>0)}print(n)

Algoritmo:

n = 1 // this will be the total
e = {x:[numLeftBounds,numRightBounds]} // imagine this as the x axis with a count of zero-crossings
a = [] // this is the stack of circles around the "cursor".  
       // values will be 1 if that circle's never had alone time, else 0
k = sort keys of e on x
for each key in k: // this is the "cursor"
  n += key[numLeftBounds] // each circle that opens has at least one space.
  k[numRightBounds].times {n += a.pop()} // pop the closing circles. if any were never alone, add 1
  k[numLeftBounds].times {a.push(alwaysAlone)} // push the opening circles
  if !a.empty():
     set the innermost circle (top of stack) to false (not never alone)
  fi
loop

Non sono terribilmente bravo con la grande notazione O, ma penso che sia O (n) poiché sto effettivamente eseguendo il ciclo attraverso ogni cerchio 3 volte (crea, sinistra, destra) e anche ordinando le chiavi della mappa (e ordino per O ( n log n) ma quello scompare). Questo è deterministico?


Se qualcuno ha qualche consiglio su come combinare il rloop e il lloop in un'unica istruzione, lo apprezzerei.
Non che Charles il

Saluti :) Mi sembra che il tuo tempo di esecuzione sia effettivamente O (n log n), a causa del tipo, che sarebbe -100. Ti farò sapere se supera tutti i casi di test.
Niklas B.

Bene, il tuo programma supera tutti i casi di test al primo tentativo. Penso che qualcosa del genere (sweepline con un certo stato mantenuto in pila) sia stata la soluzione ufficiale degli autori del problema. Il tuo programma ottiene un punteggio totale di 173
Niklas B.

@NiklasB. Grazie!
Non che Charles

Stavo provando una soluzione molto più robusta con cerchi sovrapposti .... poi ho visto che potevano intersecarsi solo in un punto.
Non che Charles

-1

JavaScript (ES6) - 255 254 caratteri - 100 250 Bonus = 155 4

R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Presuppone che la stringa di input si trovi nella variabile Se produca il numero di regioni sulla console.

R=/(\S+) (\S+)/ym;                  // Regular expression to find centre and width.
N=1;                                // Number of regions
w=l=0;                              // Maximum width and minimum left boundary.
X=[];                               // A 1-indexed array to contain the circles.
                                    // All the above are O(1)
for(;m=R.exec(S);){                 // For each circle
    X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};
                                    // Create an object with w (width), l (left boundary)
                                    // and r (right boundary) attributes.
    l=k<l?k:l;                      // Update the minimum left boundary.
    w=j<w?w:j                       // Update the maximum width.
}                                   // O(1) per iteration = O(N) total.
M=[];                               // An array.
X.map(x=>M[(x.l-l+1)*w-x.w]=x);     // Map the 1-indexed array of circles (X) to a
                                    // sparse array indexed so that the elements are
                                    // sorted by ascending left boundary then descending
                                    // width.
                                    // If there are N circles then only N elements are
                                    // created in the array and it can be treated as if it
                                    // is a hashmap (associative array) with a built in
                                    // ordering and as per the rules set in the question
                                    // is O(1) per insert so is O(N) total cost.
                                    // Since the array is sparse then it is still O(N)
                                    // total memory.
s=[];                               // An empty stack
i=0;                                // The number of circles on the stack.
M.map(x=>{                          // Loop through each circle
    while(i&&s[i-1][1]<x[1])        // Check to see if the current circle  is to the right
                                    // of the circles on the stack;
      N+=s[--i][0]?0:1;             // if so, decrement the length of the stack and if the
                                    // circle that pops off has radius equal to the total
                                    // radii of its children then increment the number of
                                    // regions by 1.

                                    // Since there can be at most N items on the stack then
                                    // there can be at most N items popped off the stack
                                    // over all the iterations; therefore this operation
                                    // has an O(N) total cost.
    i&&(s[i-1][0]-=x[0]);           // If there is a circle on the stack then this circle
                                    // is its child. Decrement the parent's radius by the
                                    // current child's radius.
                                    // O(1) per iteration
    s[i++]=x                        // Add the current circle to the stack.
  });
while(i)N+=s[--i][0]?0:1            // Finally, remove all the remaining circles from the
                                    // stack and if the circle that pops off has radius
                                    // equal to the total radii of its children then
                                    // increment the number of regions by 1.
                                    // Since there will always be at least one circle on the
                                    // stack then this has the added bonus of being the final
                                    // command so the value of N is printed to the console.
                                    // As per the previous comment on the complexity, there
                                    // can be at most N items on the stack so between this
                                    // and the iterations over the circles then there can only
                                    // be N items popped off the stack so the complexity of
                                    // all these tests on the circles on the stack is O(N).

La complessità temporale è ora O (N).

Caso di prova 1

S='2\n1 3\n5 1';
R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Uscite: 3

Caso di prova 2

S='3\n2 2\n1 1\n3 1';
R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Uscite: 5

Caso di prova 3

S='4\n7 5\n-9 11\n11 9\n0 20';
R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Uscite: 6

Caso di prova 4

S='9\n38 14\n-60 40\n73 19\n0 100\n98 2\n-15 5\n39 15\n-38 62\n94 2';
R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Uscite: 11

Caso di prova 5

S='87\n-730 4\n-836 2\n-889 1\n-913 15\n-883 5\n-908 8\n-507 77\n-922 2\n-786 2\n-782 2\n-762 22\n-776 2\n-781 3\n-913 3\n-830 2\n-756 4\n-970 30\n-755 5\n-494 506\n-854 4\n15 3\n-914 2\n-840 2\n-833 1\n-505 75\n-888 10\n-856 2\n-503 73\n-745 3\n-903 25\n-897 1\n-896 2\n-848 10\n-878 50\n-864 2\n0 1000\n-934 6\n-792 4\n-271 153\n-917 1\n-891 3\n-833 107\n-847 3\n-758 2\n-754 2\n-892 2\n-738 2\n-876 2\n-52 64\n-882 2\n-270 154\n-763 3\n-868 72\n-846 4\n-427 3\n-771 3\n-767 17\n-852 2\n-765 1\n-772 6\n-831 1\n-582 2\n-910 6\n-772 12\n-764 2\n-907 9\n-909 7\n-578 2\n-872 2\n-848 2\n-528 412\n-731 3\n-879 1\n-862 4\n-909 1\n16 4\n-779 1\n-654 68\n510 490\n-921 3\n-773 5\n-653 69\n-926 2\n-737 3\n-919 1\n-841 1\n-863 3';
R=/(\S+) (\S+)/ym;N=1;i=w=l=0;for(X=[];m=R.exec(S);){X[N++]={w:j=m[2]*1,l:k=m[1]-j,r:k+2*j};l=k<l?k:l;w=j<w?w:j}M=[];X.map(x=>M[(x.l-l+1)*w-x.w]=x);s=[];M.map(x=>{while(i&&s[i-1].r<x.r)N+=s[--i].w?0:1;i&&(s[i-1].w-=x.w);s[i++]=x});while(i)N+=s[--i].w?0:1

Uscite: 105

Versione precedente

C=S.split('\n');N=1+C.shift()*1;s=[];C.map(x=>x.split(' ')).map(x=>[w=x[1]*1,x[i=0]*1+w]).sort((a,b)=>(c=a[1]-2*a[0])==(d=b[1]-2*b[0])?b[0]-a[0]:c-d).map(x=>{while(i&&s[i-1][1]<x[1])N+=s[--i][0]?0:1;i&&(s[i-1][0]-=x[0]);s[i++]=x});while(i)N+=s[--i][0]?0:1

Con commenti:

C=S.split('\n');                    // Split the input into an array on the newlines.
                                    // O(N)
N=1+C.shift()*1;                    // Remove the head of the array and store the value as
                                    // if there are N disjoint circles then there will be
                                    // N+1 regions.
                                    // At worst O(N) depending on how .shift() works.
s=[];                               // Initialise an empty stack.
                                    // O(1)
C .map(x=>x.split(' '))             // Split each line into an array of the two values.
                                    // O(1) per line = O(N) total.
  .map(x=>[w=x[1]*1,x[i=0]*1+w])    // Re-map the split values to an array storing the
                                    // radius and the right boundary.
                                    // O(1) per line = O(N) total.

  .sort((a,b)=>(c=a[1]-2*a[0])==(d=b[1]-2*b[0])?b[0]-a[0]:c-d)
                                    // Sort the circles on increasing left boundary and
                                    // then descending radius.
                                    // O(1) per comparison = O(N.log(N)) total.
  .map(x=>{                         // Loop through each circle
    while(i&&s[i-1][1]<x[1])        // Check to see if the current circle  is to the right
                                    // of the circles on the stack;
      N+=s[--i][0]?0:1;             // if so, decrement the length of the stack and if the
                                    // circle that pops off has radius equal to the total
                                    // radii of its children then increment the number of
                                    // regions by 1.

                                    // Since there can be at most N items on the stack then
                                    // there can be at most N items popped off the stack
                                    // over all the iterations; therefore this operation
                                    // has an O(N) total cost.
    i&&(s[i-1][0]-=x[0]);           // If there is a circle on the stack then this circle
                                    // is its child. Decrement the parent's radius by the
                                    // current child's radius.
                                    // O(1) per iteration
    s[i++]=x                        // Add the current circle to the stack.
  });
while(i)N+=s[--i][0]?0:1            // Finally, remove all the remaining circles from the
                                    // stack and if the circle that pops off has radius
                                    // equal to the total radii of its children then
                                    // increment the number of regions by 1.
                                    // Since there will always be at least one circle on the
                                    // stack then this has the added bonus of being the final
                                    // command so the value of N is printed to the console.
                                    // As per the previous comment on the complexity, there
                                    // can be at most N items on the stack so between this
                                    // and the iterations over the circles then there can only
                                    // be N items popped off the stack so the complexity of
                                    // all these tests on the circles on the stack is O(N).

La complessità temporale totale è O (N) per tutto tranne l'ordinamento che è O (N.log (N)) - tuttavia sostituendo questo con un ordinamento bucket, questo ridurrà la complessità totale a O (N).

La memoria richiesta è O (N).

Indovina cosa c'è nella mia prossima lista di cose da fare ... secchio in meno di 150 caratteri. Fatto


Bucket ha una sorta solo media complessità O(n)(in realtà O(n+k)), ma O(n^2)o O(n log n)peggiore a seconda della algoritmo di ordinamento utilizzato entro secchi, così avresti bisogno di farlo in 50 caratteri.
Martin Ender,

@ m.buettner - L'ordinamento della benna può essere eseguito nella complessità peggiore di O (N). Si basa su un'attenta scelta dei bucket e su un algoritmo O (1) da assegnare ai bucket. L'ho già fatto (e dimostrato) e ho solo bisogno di trasferire il codice su JavaScript. L'algoritmo sopra è già O (N.log (N)), quindi l'unico miglioramento è ottenere un algoritmo di ordinamento O (N).
MT0

Sarei interessato a quella prova e alla corrispondente scelta di secchi. :)
Martin Ender,

cs.princeton.edu/~dpd/Papers/SCG-09-invited/… (a pagina 556) fornisce un esempio di un ordinamento di bucket O (N). archive.org/stream/PlanarityTestingByPathAddition/… (pagina 75) fornisce un esempio di ricerca DFS combinata O (N) e ordinamento bucket (la complessità temporale è discussa a pagina 76).
MT0

1
@ Mt0 tieni duro, potresti leggere la mia aggiunta alla sezione sulla complessità della domanda. Con l'ordinamento illimitato dei numeri in un tempo lineare è assolutamente impossibile
Niklas B.
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.