Desafio do Advento 1: Ajude o Papai Noel a desbloquear seu cofre atual!


18

Próximo >>

Palavras-chave descritivas (para pesquisa): Tornar duas matrizes equivalentes, Sobrepor, Matriz, Localizar

Desafio

Papai Noel teve uma história de elfos roubando presentes de seu cofre no passado, então este ano ele projetou uma fechadura que é muito difícil de quebrar, e parece ter mantido os elfos afastados este ano. Infelizmente, ele perdeu a combinação e também não sabe como abri-la! Felizmente, ele contratou você para escrever um programa para encontrar a combinação. Não precisa ser o mais curto, mas ele precisa encontrá-lo o mais rápido possível!

Ele tem uma agenda muito rígida e não pode esperar muito tempo. Sua pontuação será o tempo total de execução do seu programa multiplicado pelo número de etapas que o seu programa produz para a entrada de pontuação. Menor pontuação ganha.

Especificações

O bloqueio é uma matriz quadrada de 1s e 0s. É definido como um arranjo aleatório de 1s e 0s e precisa ser definido como um código especificado. Felizmente, o Papai Noel lembra o código necessário.

Existem alguns passos que ele pode executar. Cada etapa pode ser executada em qualquer sub-matriz contígua (ou seja, você deve selecionar uma sub-matriz totalmente delimitada por um canto superior esquerdo e inferior direito) (pode ser uma sub-matriz não quadrada):

  1. Gire 90 graus para a direita *
  2. Gire para a esquerda 90 graus *
  3. Gire 180 graus
  4. Ciclo de cada nelemento da linha para a direita ou esquerda (quebra)
  5. Ciclo de cada melemento da coluna para cima ou para baixo (envolvimentos)
  6. Virar horizontalmente
  7. Virar verticalmente
  8. Virar na diagonal principal *
  9. Virar no Main Anti-diagonal *

* somente se a sub-matriz for quadrada

Obviamente, ele também pode executar essas etapas em toda a matriz. Como 1s e 0s só podem ser trocados na matriz, mas o valor de um quadrado não pode ser alterado diretamente, o número de 1s e 0s é o mesmo para a configuração inicial e final.

Especificações de formatação + regras

Você receberá a entrada como duas matrizes quadradas (posição inicial e posição final) em qualquer formato razoável que desejar. A saída deve ser uma sequência dessas etapas em qualquer formato legível. Como esse não é um código de golfe, faça com que seja um formato facilmente verificável, mas esse não é um requisito estrito. Você pode escolher o comprimento lateral das matrizes na entrada, se desejar.

Seu programa será executado no meu computador (Linux Mint, detalhes exatos da versão disponíveis mediante solicitação, se alguém se importar: P) e cronometrarei com base na quantidade de tempo entre o momento em que pressiono "enter" na linha de comando e quando o comando sai.

Casos de teste

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. Pegue a matriz inteira. Ciclo cada coluna acima 1.
  2. Pegue as duas colunas do meio como uma sub-matriz. Ciclo cada coluna para baixo 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. Pegue a matriz inteira. Ciclo cada coluna para baixo 1.
  2. Pegue a coluna do meio. Faça um ciclo 2.
  3. Pegue as 2 primeiras linhas. Vire-o verticalmente.
  4. Pegue os 2 elementos mais à direita da linha superior. Troque-os (gire 1 para a direita / esquerda, gire na horizontal).
  5. Pegue os 2 elementos mais à esquerda da linha superior. Troque-os.

Pode haver métodos mais eficientes, mas isso não importa. Sinta-se livre para apontá-los nos comentários, se você encontrar um :)

Julgando Caso de Teste

Este caso de teste será usado para julgar seu envio. Se eu acredito que uma resposta é especializada demais para o caso de teste, tenho o direito de repetir uma entrada aleatória e rejeitar todas as respostas com o novo caso. O caso de teste pode ser encontrado aqui, onde a parte superior é o início e a parte inferior é a configuração desejada.

Se acredito que as respostas são especializadas demais, o MD5 do próximo caso de teste é 3c1007ebd4ea7f0a2a1f0254af204eed. (Isso está escrito aqui agora, para me libertar das acusações de trapaça: P)

Aplicam-se brechas padrão. Nenhuma resposta será aceita. Feliz codificação!

Nota: Eu me inspirei para esta série de desafios da Advent Of Code . Não tenho afiliação com este site

Você pode ver uma lista de todos os desafios da série consultando a seção 'Vinculado' do primeiro desafio aqui .


Informação: O caso de teste possui 192 0e 64 1, e há 256 choose 64 ≈ 1.9 × 10⁶¹matrizes alcançáveis totais . (o que é comparável a um Megaminx, e é maior do que Vingança de Rubik, ainda que muito menos do que um cubo do Professor)
user202729

Respostas:


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

Versão codificada um pouco mais rápida: Experimente online!

A entrada é números inteiros separados por espaço através da linha de comando. O primeiro número inteiro é a largura das duas matrizes. Os números inteiros restantes são seus elementos, linha por linha.

Toda permutação de uma matriz pode ser obtida apenas com os operadores de inversão horizontal e vertical, então eu ignorei o resto, exceto pela substituição de um vFlip e hFlip consecutivos na mesma região com uma rotação de 180 graus.

O programa varre cada elemento. Sempre que encontramos um elemento com o bit errado, ele olha mais à frente na matriz para encontrar um ponto que tenha o bit correto. Dividi a região de pesquisa em duas: aquelas com coordenadas de coluna iguais ou maiores e aquelas com coordenadas de coluna menores. Observe que o último deve ter uma coordenada de linha maior com base na maneira como estamos percorrendo a matriz. Se encontrarmos um bit correto na primeira região de pesquisa, podemos apenas girar 180 graus a sub-matriz que abrange os dois elementos para um total de uma operação. Se estiver na segunda região, podemos usar um giro horizontal para mover o bit correto para a mesma coluna que o bit errado e, em seguida, inverter verticalmente a sub-matriz estendendo os dois para um total de duas operações.

A saída do programa é uma matriz que deve ser mentalmente dividida em grupos de cinco. Cada grupo é (i, linha1, col1, linha2, col2), onde i é 0 para um no-op, 1 para uma rotação de 180 graus, 2 para um flip horizontal e 3 para um flip vertical. Os 4 componentes restantes descrevem a região na qual a operação é executada. Não tenho certeza se este é um formato legível.

Para o caso de teste fornecido, recebo 258 operações e dois a três milissegundos no meu computador.


@Erik the Outgolfer Não foi especificado, e a codificação embutida facilita o julgamento.
WhatToDo

Eu mudei para ter entrada da linha de comando
WhatToDo

Este formato de saída é bastante razoável. Estou recebendo 1000 números na matriz (200 operações?), De onde vem o 258? Estou um pouco confuso sobre como ler a saída disso: P
HyperNeutrino 2/17/17

Quando o executo, recebo um comprimento de 1290 (até o início das no-ops), que é cinco vezes o número de operações. O 258 é apenas o número de operações.
WhatToDo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.