Conta i quadrati


18

Sfida

Origami (carta pieghevole) è una forma d'arte creativa. Per quanto ne so, il maestro di Origami preferisce la carta quadrata. Partiamo dall'inizio: converti una carta rettangolare in una quadrata.

Quindi la carta è divisa in quadrati. Rimuoviamo il quadrato più grande che condivide un bordo più corto con la forma corrente, passo dopo passo (vedi l'immagine sotto). E se la parte rimanente dopo un passaggio è inferiore o uguale a 0.001 * (area of the original paper), la carta non può essere ulteriormente divisa. È possibile che alla fine non rimanga nulla.

Il tuo compito è calcolare quanti quadrati vengono realizzati durante il processo. Il quadrato nell'ultimo passaggio che rende impossibile dividere la carta viene conteggiato nell'output.

Esempio (un foglio di 1.350larghezza / altezza), l'output è 10:

esempio di fetta

Ingresso e uscita

Input: rapporto larghezza / altezza per la carta rettangolare, un decimale (o un numero intero senza punto) da 1.002a 1.999con un passo minimo di 0.001. È inoltre possibile utilizzare qualsiasi altro formato ragionevole che descriva il rapporto. Basta menzionarlo nella tua risposta.

Output: conteggio dei quadrati, un numero intero.

Esempio I / O

Un formato di mapping viene utilizzato per mantenere la pagina in ordine, mentre il codice non deve supportare un input di elenco né essere una funzione di mapping.

1.002 => 251
1.003 => 223
1.004 => 189
1.005 => 161
1.006 => 140
1.007 => 124
1.008 => 111
1.009 => 100

Elenco di tutte le risposte

Grazie a @LuisMendo, ecco il grafico delle risposte.

grafico

Osservazioni

  • Questo è un code-golf quindi vince il codice più breve
  • Prestare attenzione alle scappatoie standard
  • È tua libertà decidere come gestire l'input e l'output ma devono seguire le restrizioni standard.

A proposito...

  • Commenta se hai qualcosa di poco chiaro sulla sfida
  • Personalmente suggerirei che la tua risposta contenga una spiegazione se stai usando un linguaggio da golf
  • Grazie a @GregMartin, leggi la sua risposta per una buona spiegazione matematica della sfida.

Codice di esempio

Ecco una versione non modificata del codice C ++:

#include <iostream>
#include <utility>

int f (double m)
{
    double n = 1, k = 0.001;
    int cnt = 0;
    k *= m;                       // the target minimum size
    while(m*n >= k)
    {
        m -= n;                   // extract a square
        if(n > m)
            std::swap(n, m);      // keep m > n
        ++ cnt;
    }
    return cnt;
}

int main()
{
    double p;
    std::cin >> p;
    std::cout << f(p);
    return 0;
}

Tutti i calcoli relativi al codice di esempio richiedono un'accuratezza di 6 cifre decimali, che è coperta in float.


Due numeri che formano il rapporto possono essere usati come input?
Luis Mendo,

@LuisMendo sì, come tuo desiderio.
Keyu Gan,

2
Sfida ordinata!
flawr

5
L'elenco delle risposte produce un bel grafico
Luis Mendo,

1
@KeyuGan Certo, vai avanti! Fammi sapere se hai bisogno di una versione con qualche altro formato
Luis Mendo,

Risposte:


2

MATL , 19 byte

`SZ}y-htG/p1e-3>}x@

L'input è un array con i due numeri che definiscono il rapporto originale, ad esempio [1, 1.009]. (Non è necessario che i numeri siano ordinati o che uno di essi sia 1.)

Provalo online!

Spiegazione

`        % Do...while loop
  S      %   Sort array. Takes 1×2 array as input (implicit) the first time
  Z}     %   Split array into its 2 elements: first the minimum m, then the maximum M
  y      %   Duplicate m onto the top of the stack. The stack now contains m, M, m
  -      %   Subtract. The stack now contains m, M-m
  h      %   Concatenate into [m, M-m]. This is the remaining piece of paper
  t      %   Duplicate
  G/     %   Divide by input, element-wise
  p      %   Product of array. Gives ratio of current piece's area to initial area
  1e-3>  %   True if this ratio exceeds 1e-3. In that case the loop continues
}        % Finally (execute after last iteration, but still within the loop)
  x      %   Delete last piece of paper
  @      %   Push current loop counter. This is the result
         % End (implicit)
         % Display (implicit)

6

Haskell , 71 70 65 63 62 61 58 56 byte

Grazie a @xnor per alcuni ingegnosi miglioramenti!

(n#m)e|e>n*m*1e3=0|n<m=m#n$e|d<-n-m=(d#m)e+1
n!m=n#m$n*m

Provalo online!


Pensa che m==nalla fine possa essere 1>0perché è l'unica possibilità rimasta. Oppure, forse i casi potrebbero essere riorganizzati per consentire un vincolo qui.
xnor

In realtà, è necessario il caso dell'uguaglianza? Se n>mviene espanso n>=me viene scritto il primo segno di spunta e>m*n*1000, ciò dovrebbe dare 1per l'uguaglianza.
xnor

@xnor Buona idea, grazie!
flawr

1
Muoversi intorno alle guardie per 56:(n#m)e|e>n*m*1e3=0|n<m=m#n$e|d<-n-m=(d#m)e+1;n!m=n#m$n*m
xnor

Caspita, usare la d<-n-mas otherwiseè davvero pulito !!!
Flawr

4

JavaScript (ES6), 59 58 byte

f=(m,n=!(k=m/1e3,c=0))=>m*n<k?c:(c++,m-=n)<n?f(n,m):f(m,n)

Test


4

Mathematica, non competitiva (21 byte)

Questa risposta non è competitiva perché non risponde alla vera domanda posta! Ma risponde a una variante della domanda e fornisce una scusa per evidenziare alcuni interessanti calcoli matematici.

Tr@*ContinuedFraction

Funzione simbolica che prende come input un numero razionale positivo (il cui numeratore e denominatore rappresentano le dimensioni del documento originale) e restituisce un numero intero positivo. Ad esempio, Tr@*ContinuedFraction[1350/1000]restituisce 10. ( ContinuedFractionagisce diversamente sui numeri in virgola mobile a causa di problemi di precisione, motivo per cui un numero razionale è necessario come input in questo contesto.)

Un'interpretazione interessante della procedura geometrica descritta nel problema (tagliare ripetutamente i quadrati da un rettangolo) è che si tratta di un'implementazione dell'algoritmo euclideo per trovare i più grandi divisori comuni! Considera l'esempio nella domanda stessa, con il rapporto1.35, che potrebbe essere modellato avendo un pezzo di carta con dimensioni (1350,1000). Ogni volta che viene tagliato un quadrato, il numero più piccolo viene sottratto dal numero più grande; quindi i rettangoli risultanti in questo esempio hanno dimensioni (350.1000), quindi (350.650), quindi (350.300), quindi (50.300), quindi (50.250) e (50.200) e (50.150) e (50.100) e (50.100) e (50, 50) e anche (50,0) una volta rimosso l'ultimo quadrato da se stesso. Questo è esattamente il modo in cui funziona l'algoritmo euclideo (modulo la differenza tra divisione e sottrazione ripetuta), e infatti vediamo che 50 è davvero il GCD di 1350 e 1000.

Tipicamente nell'algoritmo euclideo, si tiene traccia di queste dimensioni intermedie e si scarta il numero di sottrazioni; tuttavia, si può alternativamente registrare quante volte abbiamo sottratto un numero dall'altro prima che la differenza diventi troppo piccola e dobbiamo cambiare ciò che stiamo sottraendo. Quel metodo di registrazione è precisamente la frazione continua di un numero razionale. (Le frazioni continue di numeri irrazionali, che non terminano mai, sono anche super cool, ma non rilevanti qui.) Ad esempio, nell'esempio 1350/1000, abbiamo sottratto 1000 1volte, quindi 350 2volte, quindi 300 1volte, quindi 50 6volte; pertanto la frazione continua di 1350/1000 è {1,2,1,6}. Matematicamente, abbiamo riscritto il 1350/1000 come 1+ 1 / ( 2+ 1 / ( 1+ 1 /6)), che puoi verificare.

Quindi, per questo problema, se non ti fermi quando i quadrati diventano più piccoli di una certa soglia, ma semplicemente conti tutti i quadrati finitamente prima che si fermi, allora il numero totale di quadrati è uguale al numero totale di sottrazioni, vale a dire la somma di tutti gli interi nella frazione continua - ed è esattamente ciò che Tr@*ContinuedFractioncalcola la composizione delle funzioni ! (Per il dato esempio 1,35, ottiene la risposta che il PO desidera, perché il quadrato finale è abbastanza grande da contare tutti i quadrati. Ma Tr@*ContinuedFraction[1001/1000], per esempio, produce 1001, poiché conta un solo quadrato enorme e tutti i 1000 dei piccoli quadrati 1x1000 .)


1
Anche se questo è davvero interessante, l'etichetta non competitiva è riservata alle lingue più recenti della sfida . Indipendentemente da ciò, tutte le risposte devono risolvere la sfida. Quindi, questa risposta dovrebbe davvero essere cancellata. Saresti in grado di ricostruire dall'elenco delle frazioni continue dove tagliarlo in modo che questo possa essere trasformato in una soluzione altrettanto interessante ma valida?
Martin Ender,

1
Ho avuto un prurito mentale da grattare quando scrivevo questa risposta, ma sono d'accordo che questa è una risposta degna di eliminazione secondo gli standard della comunità. (Grazie per il tuo feedback gentile ma accurato!) Se TPTB ha voglia di ritardare la sua cancellazione per 24 ore, potrei essere in grado di integrare l'approccio per fornire la risposta giusta ... In caso contrario, eliminare e senza sentimenti difficili.
Greg Martin,

3

Mathematica, 64 53 byte

({t=1,#}//.{a_,b_}/;1000a*b>#:>Sort@{++t;a,b-a};t-1)&

Una soluzione imperativa (stile C) ha esattamente la stessa lunghezza:

(For[t=a=1;b=#,1000a*b>#,If[a>b,a-=b,b-=a];++t];t-1)&

2

C (GCC / Clang), 61 59 byte

c,k;f(m,n){for(k=m*n;m*n/k;m>n?(m-=n):(n-=m))++c;return c;}

L'input è di due numeri interi (larghezza e altezza) senza punto, ad esempio f(1999,1000).

Spero che qualcuno possa salvare un byte spingendo C nel club da 58 byte. ;)


Suggerisci di rimuovere le parentesi intornom-=n
ceilingcat

1

C, 59 byte

s,a,n=1e3;C(m){for(a=m;m*n>a;s++)m>n?m-=n:(n-=m);return s;}

Provalo online

L'input è un numero intero che è il rapporto larghezza / altezza in millesimi (es. 1002 per 1.002: 1).

Versione Ungolfed

int C(int m)
{
    int n = 1000;
    int a = m;
    int s = 0;

    while (m * n > a)
    {
        if (m > n)
            m -= n;
        else
            n -= m;

        s++;
    }

    return s;
}
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.