2011-11-21 21 views
7

Vorrei per popolare una matrice n * n (n essendo dispari) nel seguente modo:Un modo semplice per popolare questa matrice?

_ _ _ 23 22 21 20 
_ _ 24 10 9 8 37 
_ 25 11 3 2 19 36 
26 12 4 1 7 18 35 
27 13 5 6 17 34 _ 
28 14 15 16 33 _ _ 
29 30 31 32 _ _ _ 

Qual è un modo semplice per farlo usando Mathematica?

+2

Possiamo presumere che 'n' è dispari? – Szabolcs

+0

@Szabolcs, mi dispiace, puoi certamente. –

+1

Solo curioso: per cosa lo utilizzerai? –

risposta

12

Con questa funzione di supporto:

Clear[makeSteps]; 
makeSteps[0] = {}; 
makeSteps[m_Integer?Positive] := 
    [email protected][ 
    Table[#, {m}] & /@ {{-1, 0}, {-1, 1}, {0, 1}, {1, 0}, {1, -1}, {0, -1}}, 1]; 

Possiamo costruire la matrice come

constructMatrix[n_Integer?OddQ] := 
    Module[{cycles, positions}, 
    cycles = (n+1)/2; 
    positions = 
     Flatten[FoldList[Plus, cycles + {#, -#}, makeSteps[#]] & /@ 
      Range[0, cycles - 1], 1]; 
    SparseArray[Reverse[positions, {2}] -> Range[Length[positions]]]]; 

Per ottenere la matrice che hai descritto, utilizzare

constructMatrix[7] // MatrixForm 

L'idea alla base di questo è a esaminare il modello che segue le posizioni dei numeri consecutivi 1 .. Puoi vedere che questi formano i cicli. Il ciclo zeroth è banale - contiene un numero 1 nella posizione {0,0} (se contiamo le posizioni dal centro). Il ciclo successivo si ottiene prendendo il primo numero (2) nella posizione {1,-1} e aggiungendo ad uno ad uno i seguenti passaggi: {0, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 0} (mentre ci spostiamo nel centro). Il secondo ciclo è simile, ma dobbiamo iniziare con {2,-2}, ripetere ciascuno dei passaggi precedenti due volte e aggiungere il sesto passo (salendo), ripetuto una sola volta: {0, -1}. Il terzo ciclo è analogo: iniziare con {3,-3}, ripetere tutti i passaggi 3 volte, eccetto lo {0,-1} che viene ripetuto solo due volte. La funzione ausiliaria makeSteps automatizza il processo. Nella funzione principale, quindi, dobbiamo raccogliere tutte le posizioni insieme e quindi aggiungerle a {cycles, cycles} poiché sono state contate dal centro, che ha una posizione {cycles,cycles}. Infine, costruiamo il SparseArray di queste posizioni.

+0

@ Mr.Wizard Ho aggiunto qualche spiegazione –

+0

Molto ben fatto. –

+0

@ Mr.Wizard Si può rimuovere il doppio 'Tranpose' e ​​usare' {cycles + #, cycles - #} & 'invece di' {#, - #} & ', per rendere il codice più breve, a scapito di alcune penalità di performance . –

8

non so la sintassi Mathematica, ma credo che si potrebbe utilizzare un algoritmo come questo:

start in the middle of the matrix 
enter a 1 into the middle 
go up-right (y-1/x+1) 
set integer iter=1 
set integer num=2 
while cursor is in matrix repeat: 
    enter num in current field 
    increase num by 1 
    repeat iter times: 
     go left (x-1/y) 
     enter num in current field 
     increase num by 1 
    repeat iter times: 
     go down-left (x-1/y+1) 
     enter num in current field 
     increase num by 1 
    repeat iter times: 
     go down (x/y+1) 
     enter num in current field 
     increase num by 1 
    repeat iter times: 
     go right (x+1/y) 
     enter num in current field 
     increase num by 1 
    repeat iter times: 
     go up-right (x+1/y-1) 
     enter num in current field 
     increase num by 1 
    repeat iter-1 times: 
     go up (x/y-1) 
     enter num in current field 
     increase num by 1 
    go up-up-right (y-2/x+1) 
    increase iter by 1 

è anche possibile convertire abbastanza facilmente questo algoritmo in una versione funzionale o in una coda ricorsione.

Bene, si dovrà controllare nel ciclo while se non si è fuori dai limiti. Se n è dispari, allora si può solo contare num mentre:

m = floor(n/2) 
num <= n*n - (m+m*m) 

Sono abbastanza sicuro che ci sia un algoritmo semplice ma questo è il più intuitivo per me.

+1

Anche se qualcosa del genere funziona, ed è semplice, penso che il punto della domanda sia come sfruttare le funzionalità incorporate di Mathematica e i comandi di programmazione funzionale per creare qualcosa di più semplice e compatto :-) – Szabolcs

+0

Mentre eseguivo la mia versione indipendentemente, ho appena capito che questo è lo stesso algoritmo con cui ho finito, appena fatto proceduralmente. +1. –

+0

@Leonid Devo ammettere che mi sono perso nel bel mezzo della lettura di questo e ho pensato "Aspetterò solo una risposta * Mathematica *". PeterT: +1 –

4

I numeri magici sulla partenza diagonale a 1 e salendo a destra si può arrivare a da

f[n_] := 2 Sum[2 m - 1, {m, 1, n}] + UnitStep[n - 3] Sum[2 m, {m, 1, n - 2}] 

In := [email protected]@5 
Out := {2, 8, 20, 38, 62} 

Con questo dovrebbe essere facile da configurare un SparseArray. Ci giocherò un po 'e vedrò quanto sia difficile.

+1

Puoi ridurlo a '2 - 3 n + 3 n^2' – Szabolcs

+0

Ancora più semplice è la definizione ricorsiva' f [-1] = 2; f [i _]: = 6i + f [i-1 ]; ' – Timo

+0

Come al solito http://oeis.org/search?q=1%2C2%2C8%2C20%2C38&sort=&language=english&go=Search :) –

3

Una soluzione parziale, utilizzando l'immagine procssing:

enter image description here

Image /@ ([email protected](ImageData /@ 
    NestList[ 
     Fold[ImageAdd, 
     p = #, (HitMissTransform[p, #, Padding -> 0] & /@ 
      {{{1}, {-1}}, 
      {{-1}, {-1}, {1}}, 
      {{1, -1, -1}}, 
      {{-1, -1, 1}}, 
      {{-1, -1, -1, -1}, {-1, -1, -1, -1}, {1, 1, -1, -1}}, 
      {{-1, -1, -1, 1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}}})] &, img, 4])) 

enter image description here

+0

Potrebbe [questa domanda] (http://dsp.stackexchange.com/q/675/77) essere di vostro interesse? – abcd

+0

@yoda Bella domanda e non facile affatto. Penso che si dovrebbe cercare di riconoscere le ellissi rotanti. –

+0

Sarebbe bello se tu lo dessi una possibilità :) Posso anche bontà per potenziarti: D Ci sono alcune domande di elaborazione delle immagini che girano intorno ([eccone un'altra interessante] (http://dsp.stackexchange.com/ domande/374/river-detection-in-text)), ma non abbastanza persone ben informate per rispondere. Un sacco di gente sta postando risposte a metà assed ... – abcd

4

Prima versione:

i = 10; 
a = b = c = Array[0 &, {2 (2 i + 1), 2 (2 i + 1)}]; 
f[n_] := 3*n*(n + 1) + 1; 
k = f[i - 2]; 
p[i_Integer] := 
    [email protected][ 
    -x + y < i - 1 && -x + y > -i + 1 && 
    (2 i + 1 - x)^2 + (2 i + 1 - y)^2 <= 2 i i - 2 && 
    3 i - 1 > x > i + 1 && 
    3 i - 1 > y > i + 1, {x, y}, Integers]; 

((a[[Sequence @@ #]] = 1) & /@ ({x, y} /. {p[i]})); 
((a[[Sequence @@ (# + {2, 2})]] = 0) & /@ ({x, y} /. {p[i - 1]})); 

(b[[Sequence @@ #]] = k--)&/@((# + 2 i {1, 1}) &/@ (SortBy[(# - 2 i {1, 1}) &/@ 
     Position[a, 1], 
     [email protected](Mod[-10^-9 - Pi/4 + ArcTan[Sequence @@ #], 2 Pi]) &])); 
c = Table[b[[2 (2 i + 1) - j, k]], {j, 2 (2 i + 1) - 1}, 
            {k, 2 (2 i + 1) - 1}]; 
MatrixPlot[c] 

enter image description here

Modifica

uno migliore:

genMat[m_] := Module[{f, k, k1, i, n, a = {{1}}}, 
    f[n_] := 3*n*(n + 1) + 1; 
    For[n = 1, n <= m, n++, 
    a = ArrayPad[a, 1]; 
    k1 = (f[n - 1] + (k = f[n]) + 2)/2 - 1; 
    For[i = 2, i <= n + 1, i++, a[[i, 2n + 1]] = k--; a[[2-i+2 n, 1]] = k1--]; 
    For[i = n + 2, i <= 2 n + 1, i++, a[[i, 3n+2-i]] = k--; a[[-i,i-n]] = k1--]; 
    For[i = n, i >= 1, i--, a[[2n+1, i]] = k--;a[[1, -i + 2 n + 2]] = k1--]; 
    ]; 
    [email protected][a]; 
    ] 

genMat[5] 
+1

Sembra molto interessante; potresti spiegarlo per favore? –

+1

@Mr. L'attuale incarnazione del codice è ancora troppo complicata. Lo pulirò e commenterò non appena avrò del tempo libero. Ci sono due idee principali (nulla di brillante): 1) descrivi l'esagono geometricamente e lascia che Reduce [] trovi i bordi e 2) Ordina gli elementi del bordo per l'angolo sotteso dal centro del poligono. La terza idea non è la mia f [n_]: = 3 * n * (n + 1) + 1 viene da qui https://oeis.org/search?q=crystal+ball&language=english&go=Search –

+0

Non riesco a immaginare questo essere altamente efficienti, ma +1 per un approccio completamente diverso. –

Problemi correlati