"Fülle das Gitter" -Problem


36

Eine Herausforderung mit einfachen Regeln, aber nicht trivialen Algorithmen. :-)

Aufgabe

Nehmen Sie die Eingabe in Form von durch Leerzeichen getrennten ganzen Zahlen vor:

N A B S

Wobei N die Seitenlänge einer 2D-Quadratmatrix ist, die mit eindeutigen Zahlen (Ganzzahlen) zwischen A und B einschließlich gefüllt ist . Für jede Zeile und Spalte in dieser Matrix ist die Summe immer dieselbe: S. (Mit anderen Worten, die Matrix ist ein halbmagisches Quadrat).

Hinweis:

Alle Zahlen sind positiv. Ausnahme ist A, das 0 sein kann.

Beispiele

Zum

3 1 10000 2015

eine gültige lösung wäre

Bildbeschreibung hier eingeben

Zum

8 1 300 500

eine gültige lösung wäre

Bildbeschreibung hier eingeben

Ausgabe

Die Ausgabe sollte eine ASCII-Tabelle sein. Beispiel für das erste Beispiel oben:

 384  159 1472
1174  499  342
 457 1357  201

Rechtsbündige Ganzzahlen, die mit Leerzeichen aufgefüllt sind. Die Breite jeder Spalte ist die Breite der größten Ganzzahl in dieser Spalte.

Wertung

Das ist , also gewinnt der kürzeste Code in Bytes. Es gelten Standard-Regelungslücken (insbesondere bei integrierten Funktionen zur Lösung dieses Problems). Sie müssen sich nicht um falsche oder anderweitig unmögliche Eingaben (einschließlich negativer Zahlen) kümmern. Bitte geben Sie in Ihrer Antwort (obligatorisch) ein Beispiel für das zweite Beispiel oben an.


1
Dürfen wir Zufallszahlen zwischen A und B generieren, bis sie korrekt summiert sind und eindeutig sind?
Lirtosiast

Nur um zu überprüfen, A, B, und Nkann negativ sein?
Xnor

2
minxomat, ich sage nicht, dass es die beste Lösung ist, die ich finden kann, ich sage, dass es die kürzeste sein kann.
Lirtosiast

3
@LuisMendo Sie müssen eine Beispielausgabe entsprechend der Aufgabe erstellen. Wenn Sie dies mit einem Brute-Force-Ansatz in Ihrem Leben schaffen, wäre ich beeindruckt. :-). Ich könnte es ausschließen, aber es wäre zu unscharf, da die beliebteste Lösung (die GA ist) immer noch Zufälligkeit beinhaltet. Außerdem möchte ich die Regeln nicht ändern, wenn jemand bereits an einer Lösung arbeitet.
Mittwoch,

1
@ Minxomat Alle Ihre drei Argumente sind sehr gute Punkte :-)
Luis Mendo

Antworten:


19

CJam, 119 91 Bytes

q~:M;),>:R;(:L{{R{ML)d/-Y#)mr}$L/L<2{{M1$:+-+}%z}*:U:+__O|=R*-}gU{:s_:,:e>f{Se[}}%zSf*N*}M?

Dies ist ein nachweislich korrekter, nicht deterministischer Ansatz.

Auf meinem Desktop ist der zweite Testfall in der Regel in weniger als 10 Minuten abgeschlossen.

Der erste Fall wird sofort beendet. Probieren Sie es online im CJam-Interpreter aus .

Probelauf

$ cjam grid.cjam <<< '8 1 300 500'
77  66  37 47  56  46 86  85
63 102  70 72  49  54 81   9
62  69  58 57  71  17 48 118
64  65  67 87  53  44 80  40
73  60  55 89  51  76 84  12
68  59  28 78  74  38 50 105
61  75  52 43 125  83 42  19
32   4 133 27  21 142 29 112

Idee

Ohne zeitliche Begrenzung könnten wir nur nach dem Zufallsprinzip Quadrate erzeugen, bis wir ein gültiges Quadrat gefunden haben. Dieser Ansatz baut auf dieser Idee auf und fügt zwei Optimierungen hinzu:

  • Anstatt ein Quadrat der Seitenlänge N pseudozufällig zu erzeugen , erzeugen wir Quadrate der Seitenlänge N-1 , fügen eine Spalte hinzu, um ein N × (N-1) -Rechteck zu bilden, dessen Zeilen die Summe S haben , und dann eine Zeile, um ein Quadrat von zu bilden Seitenlänge N, deren Spalten die Summe S haben .

    Da die Summe der Elemente aller Spalten NS und die Summe der Elemente der ersten N-1 sein wird Zeilen (N-1) S , wird die letzte Reihe auch sum hat S .

    Dieser Vorgang kann jedoch zu einer ungültigen Matrix führen, da nicht garantiert werden kann, dass alle Elemente der letzten Zeile und Spalte eindeutig sind oder in den Bereich fallen [A ... B] fallen .

  • Auswählen eines Quadrats eindeutiger Ganzzahlen in [A ... B] und Seitenlänge N-1 nach dem Zufallsprinzip wäre viel zu lang. Wir müssen irgendwie Quadrate priorisieren, die eine höhere Wahrscheinlichkeit haben, ein gültiges Quadrat mit der Seitenlänge N zu erhalten, nachdem wir den im vorherigen Aufzählungspunkt beschriebenen Prozess angewendet haben.

    Vorausgesetzt, jede Zeile und Spalte muss eine Summe von haben S , haben seine Elemente einen Durchschnitt von S / N . Wenn Sie also mehr Elemente in der Nähe dieses Durchschnitts auswählen, erhöhen Sie unsere Chancen.

    Für jedes I in [A ... B] wählen wir pseudozufällig einen Float zwischen 0 und (I - S / N) 2 + 1 und sortieren die Elemente von [A ... B] nach den ausgewählten Floats. Wir behalten die ersten N 2 -Zahlen und ordnen sie in Lesereihenfolge in einem Quadrat ein.

    Unter der Annahme einer vollkommen gleichmäßigen Verteilung aller reellen Zahlen zwischen 0 und (I - S / N) 2 + 1 in jedem Schritt haben alle Quadrate eine Wahrscheinlichkeit ungleich Null, ausgewählt zu werden, was bedeutet, dass der Prozess schließlich beendet wird.

Code

q~          e# Read all input from STDIN and evaluate it.
:M;         e# Save "S" in M and discard it from the stack.
),>:R;      e# Transform "A B" into [A ... B], save in R and discard.
(:L         e# Save "N - 1" in L and keep it on the stack.
{           e# If L is non-zero:
  {         e#   Do:
    R{      e#     For each I in R:
      ML)d/ e#       Compute M/Double(L+1).
      -Y#   e#       Subtract the result from I and square the difference.
      )mr   e#       Add 1 and pick a non-negative Double below the result.
    }$      e#     Sort the values of I according to the picks.
    L/      e#     Split the shuffled R into chunks of length L.
    L<      e#     Keep only the first L chunks.
    2{      e#     Do twice:
      {     e#       For each row of the  L x L array.
        M1$ e#       Push M and a copy of the row.
        :+- e#       Add the integers of the row and subtract their sum from M.
        +   e#       Append the difference to the row.
      }%    e#
      z     e#       Transpose rows and columns.
    }*      e#
    :U:+    e#     Save the result in U and concatenate its rows.
    __O|    e#     Push two copies. Deduplicate the second copy.
    =R*     e#     Push R if all elements are unique, an empty array otherwise.
    -       e#     Remove the result's elements from U's elements.
  }g        e#   If the resulting array is non-empty, repeat the loop.
  U{        e#   For each row in U:
    :s      e#     Convert its integers into strings.
    _:,     e#     Copy and replace each string with its length.
    :e>     e#     Compute the maximum length.
    f{      e#     For each integer, push the maximum length; then
      Se[   e#       Left-pad the integer with spaces to that length.
    }       e#
  }%        e#
  z         e#   Transpose rows with columns.
  Sf*N*     e#   Join columns by spaces, rows by linefeeds.
}M?         e# Else, push M.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.