Advent Challenge 1: Aiuta Babbo Natale a sbloccare il suo caveau attuale!


18

Successivo >>

Parole chiave descrittive (per la ricerca): Rendi equivalenti due matrici, Sovrapponi, Matrice, Trova

Sfida

Babbo Natale ha avuto una storia di elfi che hanno rubato regali dalla sua volta in passato, quindi quest'anno ha progettato una serratura che è molto difficile da decifrare, e sembra che abbia tenuto fuori gli elfi quest'anno. Sfortunatamente, ha perso la combinazione e non riesce nemmeno a capire come aprirla! Fortunatamente, ti ha assunto per scrivere un programma per trovare la combinazione. Non deve essere il più corto, ma deve trovarlo il più velocemente possibile!

Ha un programma molto rigido e non può permettersi di aspettare molto a lungo. Il tuo punteggio sarà il tempo di esecuzione totale del tuo programma moltiplicato per il numero di passaggi emessi dal tuo programma per l'input del punteggio. Il punteggio più basso vince.

specificazioni

Il lucchetto è una matrice quadrata di 1 e 0 secondi. È impostato su una disposizione casuale di 1 e 0 e deve essere impostato su un codice specificato. Fortunatamente, Babbo Natale ricorda il codice richiesto.

Ci sono alcuni passaggi che può eseguire. Ogni passaggio può essere eseguito su qualsiasi sott matrice secondaria contigua (vale a dire, è necessario selezionare una matrice secondaria interamente delimitata da un angolo superiore sinistro e inferiore destro) (può essere una matrice secondaria non quadrata):

  1. Ruota a destra di 90 gradi *
  2. Ruota a sinistra di 90 gradi *
  3. Ruota di 180 gradi
  4. Scorri ogni nelemento di riga a destra o a sinistra (avvolge)
  5. Scorri gli melementi di ogni colonna verso l'alto o verso il basso (avvolge)
  6. Capovolgi orizzontalmente
  7. Capovolgi verticalmente
  8. Capovolgi sulla diagonale principale *
  9. Capovolgi l'anti-diagonale principale

* solo se la matrice secondaria è quadrata

Naturalmente, può anche eseguire questi passaggi sull'intera matrice. Dato che 1 e 0 possono essere scambiati solo sulla matrice ma il valore di un quadrato non può essere modificato direttamente, il numero di 1 e 0 è lo stesso per la configurazione iniziale e finale.

Formattazione di specifiche + regole

Ti verrà dato l'input come due matrici quadrate (posizione iniziale e posizione finale) in qualsiasi formato ragionevole tu voglia. L'output dovrebbe essere una sequenza di questi passaggi in qualsiasi formato leggibile. Poiché non si tratta di code-golf, rendilo un formato facilmente verificabile, ma non è un requisito rigoroso. Se lo desideri, puoi scegliere di prendere la lunghezza laterale delle matrici nell'input.

Il tuo programma verrà eseguito sul mio computer (Linux Mint, dettagli esatti della versione disponibili su richiesta se a qualcuno interessa: P) e lo farò in base al periodo di tempo che intercorre tra il momento in cui premo "invio" sulla riga di comando e quando il il comando termina.

Casi test

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. Prendi l'intera matrice. Scorri verso l'alto ogni colonna 1.
  2. Prendi le due colonne centrali come sotto-matrice. Scorri verso il basso ogni colonna 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. Prendi l'intera matrice. Scorri verso il basso ogni colonna 1.
  2. Prendi la colonna centrale. Abbassalo 2.
  3. Prendi le prime 2 file. Capovolgi verticalmente.
  4. Prendi i 2 elementi più a destra della riga superiore. Scambiali (ruota a destra / a sinistra 1, capovolgi orizzontalmente).
  5. Prendi i 2 elementi più a sinistra della riga superiore. Scambiali.

Potrebbero esserci metodi più efficienti, ma non importa. Sentiti libero di segnalarli nei commenti se ne trovi uno :)

Giudicare il caso di prova

Questo caso di test verrà utilizzato per giudicare la tua richiesta. Se credo che una risposta sia troppo specializzata per il caso di test, ho il diritto di ripetere un input casuale e di giudicare tutte le risposte con il nuovo caso. Il caso di test può essere trovato qui dove la parte superiore è l'inizio e la parte inferiore è la configurazione desiderata.

Se credo che le risposte si stiano specializzando troppo, l'MD5 del prossimo caso di test lo è 3c1007ebd4ea7f0a2a1f0254af204eed. (Questo è scritto qui in questo momento per liberarmi dalle accuse di barare: P)

Si applicano scappatoie standard. Nessuna risposta sarà accettata. Buona programmazione!

Nota: ho tratto ispirazione per questa serie di sfide da Advent Of Code . Non ho affiliazione con questo sito

Puoi vedere un elenco di tutte le sfide della serie guardando la sezione "Linked" della prima sfida qui .


Informazioni: il caso di test ha 192 0'e 64 1' e ci sono 256 choose 64 ≈ 1.9 × 10⁶¹matrici raggiungibili totali . (che è paragonabile a una Megaminx, ed è più grande di una vendetta di Rubik, anche se molto meno di un cubo di un professore)
user202729

Risposte:


1

Giava

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);
	}
}

Versione hardcoded leggermente più veloce: provalo online!

L'input è numeri interi separati da spazio tramite la riga di comando. Il primo numero intero è la larghezza delle due matrici. Gli interi rimanenti sono i loro elementi, riga per riga.

Ogni permutazione di una matrice può essere ottenuta solo con gli operatori di flip orizzontale e flip verticale, quindi ho ignorato il resto tranne che per sostituire un vFlip e hFlip consecutivi nella stessa regione con una rotazione di 180 gradi.

Il programma esegue la scansione di ciascun elemento. Ogni volta che incontriamo un elemento che ha il bit sbagliato, guarda più avanti attraverso l'array per trovare un punto con il bit corretto. Ho diviso la regione di ricerca in due: quelli con coordinate di colonna uguali o più grandi e quelli con coordinate di colonna più piccole. Nota che quest'ultimo deve avere una coordinata di riga più grande in base al modo in cui attraversiamo l'array. Se troviamo un bit corretto nella prima area di ricerca, possiamo semplicemente ruotare di 180 gradi la sott matrice secondaria che copre i due elementi per un totale di un'operazione. Se si trova nella seconda regione, possiamo usare una rotazione orizzontale per spostare il bit corretto nella stessa colonna del bit sbagliato e quindi capovolgere verticalmente la sotto-matrice che abbraccia i due per un totale di due operazioni.

L'output del programma è un array che dovrebbe essere suddiviso mentalmente in gruppi di cinque. Ogni gruppo è (i, riga1, col1, riga2, col2) dove i è 0 per un no-op, 1 per una rotazione di 180 gradi, 2 per una rotazione orizzontale e 3 per una rotazione verticale. I restanti 4 componenti descrivono la regione su cui viene eseguita l'operazione. Non sono sicuro che si tratti di un formato leggibile.

Per il dato caso di test, ottengo 258 operazioni e da due a tre millisecondi sul mio computer.


@Erik the Outgolfer Non è stato specificato e l'hard-coding rende più facile giudicare.
WhatToDo

L'ho modificato per ricevere input dalla riga di comando
WhatToDo

Questo formato di output è abbastanza ragionevole. Ricevo 1000 numeri nell'array (200 operazioni?), Quindi da dove provengono i 258? Sono un po 'confuso su come leggere l'output da questo: P
HyperNeutrino

Quando lo eseguo, ottengo una lunghezza di 1290 (fino all'avvio delle operazioni non operative), che è cinque volte il numero di operazioni. Il 258 è solo il numero di operazioni.
WhatToDo
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.