Advent Challenge 1: Hilf dem Weihnachtsmann, sein gegenwärtiges Gewölbe freizuschalten!

18

Weiter >>

Beschreibende Schlüsselwörter (für die Suche): Zwei Matrizen gleichsetzen, Überlappen, Array, Suchen

Herausforderung

Der Weihnachtsmann hatte in der Vergangenheit eine Geschichte, in der Elfen Geschenke aus seinem Tresor gestohlen haben. Deshalb entwarf er dieses Jahr ein Schloss, das sehr schwer zu knacken ist, und es scheint die Elfen in diesem Jahr davon abzuhalten. Leider hat er die Kombination verloren und kann auch nicht herausfinden, wie man sie öffnet! Glücklicherweise hat er Sie beauftragt, ein Programm zu schreiben, um die Kombination zu finden. Es muss nicht das kürzeste sein, aber er muss es so schnell wie möglich finden!

Er hat einen sehr strengen Zeitplan und kann es sich nicht leisten, sehr lange zu warten. Ihre Punktzahl ist die Gesamtlaufzeit Ihres Programms multipliziert mit der Anzahl der Schritte, die Ihr Programm für die Bewertungseingabe ausgibt. Die niedrigste Punktzahl gewinnt.

Spezifikationen

Die Sperre ist eine quadratische Matrix aus Einsen und Nullen. Es ist auf eine zufällige Anordnung von Einsen und Nullen festgelegt und muss auf einen bestimmten Code festgelegt werden. Glücklicherweise merkt sich der Weihnachtsmann den erforderlichen Code.

Es gibt ein paar Schritte, die er ausführen kann. Jeder Schritt kann für jede zusammenhängende Untermatrix ausgeführt werden (dh Sie müssen eine Untermatrix auswählen, die vollständig von einer oberen linken und unteren rechten Ecke begrenzt ist) (es kann sich um eine nicht quadratische Untermatrix handeln):

  1. 90 Grad nach rechts drehen *
  2. 90 Grad nach links drehen *
  3. 180 Grad drehen
  4. Zyklus jedes Zeilenelement nach nrechts oder links (Zeilenumbrüche)
  5. Wechseln Sie die einzelnen Spaltenelemente nach moben oder unten (Zeilenumbrüche).
  6. Horizontal spiegeln
  7. Vertikal spiegeln
  8. Flip auf der Hauptdiagonale *
  9. Drehe die Haupt-Anti-Diagonale um *

* nur wenn die Submatrix quadratisch ist

Natürlich kann er diese Schritte auch auf der gesamten Matrix ausführen. Da Einsen und Nullen nur in der Matrix vertauscht werden können, der Wert eines Quadrats jedoch nicht direkt geändert werden kann, ist die Anzahl der Einsen und Nullen für die Start- und Endkonfiguration gleich.

Formatierungsspezifikationen + Regeln

Sie erhalten die Eingabe als zwei quadratische Matrizen (Startposition und Endposition) in einem beliebigen Format. Die Ausgabe sollte eine Folge dieser Schritte in einem beliebigen lesbaren Format sein. Da dies kein Code-Golf ist, machen Sie es bitte zu einem leicht überprüfbaren Format, aber das ist keine strenge Anforderung. Sie können wählen, ob Sie die Seitenlänge der Matrizen in der Eingabe verwenden möchten.

Ihr Programm wird auf meinem Computer ausgeführt (Linux Mint, genaue Versionsangaben auf Anfrage, falls dies von Belang ist: P). Die Zeitspanne zwischen dem Drücken der Eingabetaste in der Befehlszeile und dem Zeitpunkt, zu dem das Programm ausgeführt wird, hängt von der Zeit ab Befehl beendet.

Testfälle

1 0 0 1    0 0 0 0
0 1 1 0 -> 0 0 0 0
0 1 1 0 -> 1 1 1 1
1 0 0 1    1 1 1 1
  1. Nehmen Sie die gesamte Matrix. Jede Säule hochfahren 1.
  2. Nehmen Sie die beiden mittleren Spalten als Untermatrix. Fahren Sie jede Säule nach unten. 2.
1 0 1 0 1    0 1 0 1 0
0 1 0 1 0    1 0 1 0 1
1 0 1 0 1 -> 0 1 1 1 0
0 1 0 1 0    1 0 1 0 1
1 0 1 0 1    0 1 0 1 0
  1. Nehmen Sie die gesamte Matrix. Fahren Sie jede Säule nach unten. 1.
  2. Nimm die mittlere Spalte. Fahren Sie es runter 2.
  3. Nimm die obersten 2 Reihen. Drehe es vertikal.
  4. Nimm die obersten 2 Elemente ganz rechts. Tauschen Sie sie aus (drehen Sie sie 1 nach rechts / links, drehen Sie sie horizontal).
  5. Nimm die 2 Elemente ganz links in der obersten Reihe. Tausche sie aus.

Es könnte effizientere Methoden geben, aber das spielt keine Rolle. Fühlen Sie sich frei, in den Kommentaren darauf hinzuweisen, wenn Sie einen finden :)

Testfall beurteilen

Dieser Testfall wird verwendet, um Ihre Einreichung zu beurteilen. Wenn ich der Meinung bin, dass sich eine Antwort zu sehr auf den Testfall spezialisiert hat, kann ich eine zufällige Eingabe wiederholen und alle Antworten mit dem neuen Fall neu bewerten. Den Testfall finden Sie hier wo oben der Anfang und unten die gewünschte Konfiguration ist.

Wenn ich glaube, dass sich die Antworten zu sehr spezialisieren, ist das MD5 der nächste Testfall 3c1007ebd4ea7f0a2a1f0254af204eed. (Dies ist hier gerade geschrieben, um mich von den Vorwürfen des Betrugs zu befreien: P)

Es gelten Standardlücken. Es wird keine Antwort akzeptiert. Viel Spaß beim Codieren!

Hinweis: Ich habe mich für diese Herausforderungsserie von Advent Of Code inspirieren lassen . Ich habe keine Zugehörigkeit zu dieser Site

Eine Liste aller Herausforderungen in der Serie finden Sie im Abschnitt "Verknüpft" der ersten Herausforderung hier .

HyperNeutrino
quelle
Information: Der Testfall hat 192 0und 64 1, und es gibt insgesamt 256 choose 64 ≈ 1.9 × 10⁶¹erreichbare Matrizen. (Das ist vergleichbar mit einer Megaminx und ist größer als die Rache eines Rubiks, obwohl viel weniger als der Würfel eines Professors)
user202729

Antworten:

1

Java

import java.util.Arrays;

public class SantaMatrix4 {
	
	public static void flipV(int[][] matrix, int row1, int col1, int row2, int col2) {
		for (int row = row1; row <= (row2 - row1) / 2 + row1; row++) {
			for (int col = col1; col <= col2; col++) {
				int tmp = matrix[row][col];
				matrix[row][col] = matrix[row2 - row + row1][col];
				matrix[row2 - row + row1][col] = tmp;
			}
		}
	}
	
	public static void flipH(int[][] matrix, int row1, int col1, int row2, int col2) {
		for (int row = row1; row <= row2; row++) {
			for (int col = col1; col <= (col2 - col1) / 2 + col1; col++) {
				int tmp = matrix[row][col];
				matrix[row][col] = matrix[row][col2 - col + col1];
				matrix[row][col2 - col + col1] = tmp;
			}
		}
	}

	public static void main(String[] args) {
		int counter = 0;
		int n = Integer.parseInt(args[counter++]);
		int[][] matrix1 = new int[n][n];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				matrix1[i][j] = Integer.parseInt(args[counter++]);
			}
		}
				
		int[][] matrix2 = new int[n][n];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				matrix2[i][j] = Integer.parseInt(args[counter++]);
			}
		}
			
		int[] ops = new int[5 * matrix1.length * matrix1.length * 2];
		int numOps = 0;
		int opsI = 0;
		
		for (int row = 0; row < n; row++) {
			for (int col = 0; col < n; col++) {
				int goal = matrix2[row][col];
				boolean gotIt = false;
				
				//Look for required number to the right
				for (int i = row; i < n && !gotIt; i++) {
					for (int j = col; j < n && !gotIt; j++) {
						if (i == row && j == col) continue;
						if (matrix1[i][j] == goal) {
							flipH(matrix1, row, col, i, j);
							flipV(matrix1, row, col, i, j);
							ops[opsI++] = 1;
							ops[opsI++] = row;
							ops[opsI++] = col;
							ops[opsI++] = i;
							ops[opsI++] = j;
							numOps++;
							
							gotIt = true;
						}
					}
				}

				//Look for required number below and to the left
				for (int i = row + 1; i < n && !gotIt; i++) {
					for (int j = 0; j < col && !gotIt; j++) {
						if (matrix1[i][j] == goal) {
							flipH(matrix1, i, j, i, col);
							ops[opsI++] = 2;
							ops[opsI++] = i;
							ops[opsI++] = j;
							ops[opsI++] = i;
							ops[opsI++] = col;
							
							flipV(matrix1, row, col, i, col);
							ops[opsI++] = 3;
							ops[opsI++] = row;
							ops[opsI++] = col;
							ops[opsI++] = i;
							ops[opsI++] = col;
							
							numOps += 2;
							gotIt = true;
						}
					}
				}
				
			}
		}

		System.out.println(Arrays.toString(ops));
		System.out.println(numOps);
	}
}

Etwas schnellere, fest codierte Version: Probieren Sie es online aus!

Die Eingabe erfolgt durch durch Leerzeichen getrennte Ganzzahlen über die Befehlszeile. Die erste Ganzzahl ist die Breite der beiden Matrizen. Die verbleibenden ganzen Zahlen sind ihre Elemente, Zeile für Zeile.

Jede Permutation einer Matrix kann nur mit den Operatoren "Horizontal" und "Vertikal" erhalten werden. Ich habe den Rest ignoriert, bis auf das Ersetzen eines aufeinanderfolgenden vFlip und hFlip in derselben Region durch eine Drehung um 180 Grad.

Das Programm durchsucht jedes Element. Immer wenn wir auf ein Element stoßen, das das falsche Bit hat, schaut es weiter vorne durch das Array, um einen Punkt zu finden, der das richtige Bit hat. Ich habe den Suchbereich in zwei Bereiche unterteilt: die mit der gleichen oder einer größeren Spaltenkoordinate und die mit der kleineren Spaltenkoordinate. Beachten Sie, dass letztere eine größere Zeilenkoordinate haben müssen, je nachdem, wie wir das Array durchlaufen. Wenn wir im ersten Suchbereich ein korrektes Bit finden, können wir die Submatrix, die die beiden Elemente überspannt, für insgesamt eine Operation nur um 180 Grad drehen. Wenn es sich in der zweiten Region befindet, können wir ein horizontales Flip verwenden, um das richtige Bit in die gleiche Spalte wie das falsche Bit zu verschieben, und dann die Submatrix, die die beiden überspannt, für insgesamt zwei Operationen vertikal umdrehen.

Die Ausgabe des Programms ist ein Array, das mental in Fünfergruppen aufgeteilt werden sollte. Jede Gruppe ist (i, row1, col1, row2, col2), wobei i 0 für ein No-Op, 1 für eine Drehung um 180 Grad, 2 für ein horizontales Flip und 3 für ein vertikales Flip ist. Die restlichen 4 Komponenten beschreiben die Region, in der die Operation ausgeführt wird. Ich bin nicht sicher, ob dies ein lesbares Format ist.

Für den gegebenen Testfall erhalte ich 258 Operationen und zwei bis drei Millisekunden auf meinem Computer.

Was ist zu tun
quelle
@Erik the Outgolfer Es wurde nicht spezifiziert und die Hardcodierung erleichtert die Beurteilung.
WhatToDo
Ich habe es geändert, um Eingaben von der Befehlszeile zu übernehmen
WhatToDo
Dieses Ausgabeformat ist ausreichend. Ich bekomme zwar 1000 Nummern im Array (200 Operationen?) Also woher kommt der 258? Ich bin ein wenig verwirrt, wie ich die Ausgabe hiervon lesen soll: P
HyperNeutrino
Wenn ich es ausführe, erhalte ich eine Länge von 1290 (bis die No-Ops beginnen), was dem Fünffachen der Anzahl der Operationen entspricht. Der 258 ist nur die Anzahl der Operationen.
WhatToDo