Advent Challenge 1 : 산타가 현재 금고를 열 수 있도록 도와주세요!


18

다음 >>

설명 키워드 (검색 용) : 두 개의 행렬을 동일하게 만들기, 겹침, 배열, 찾기

도전

산타는 과거에 그의 금고에서 선물을 훔친 엘프의 역사를 가지고 있었기 때문에 올해에는 금이 오기 어려운 자물쇠를 설계했으며 올해 엘프를 지키지 못한 것 같습니다. 불행히도, 그는 조합을 잃어 버렸고 그것을 여는 방법을 알 수 없습니다! 다행히 그는 조합을 찾기위한 프로그램을 작성하도록 고용했습니다. 최단 일 필요는 없지만 가능한 빨리 찾아야합니다!

그는 매우 엄격한 일정을 가지고 있으며 오래 기다릴 여유가 없습니다. 점수는 프로그램의 총 런타임에 점수 입력에 대한 프로그램 출력 단계 수를 곱한 값입니다. 최저 점수가 이깁니다.

명세서

잠금은 1과 0의 정사각 행렬입니다. 1과 0의 임의 배열로 설정되며 지정된 코드로 설정해야합니다. 다행히 산타는 필요한 코드를 기억합니다.

그가 수행 할 수있는 몇 가지 단계가 있습니다. 각 단계는 인접한 하위 행렬에서 수행 할 수 있습니다 (즉, 왼쪽 상단 및 오른쪽 하단 모서리로 완전히 경계가 지정된 하위 행렬을 선택해야 함) (비 정사각 하위 행렬 일 수 있음).

  1. 오른쪽으로 90도 회전 *
  2. 왼쪽으로 90도 회전 *
  3. 180도 회전
  4. 각 행 n요소를 좌우로 순환 (랩)
  5. 각 열 m요소를 위 또는 아래로 순환 (랩)
  6. 수평으로 뒤집기
  7. 세로로 뒤집기
  8. 주 대각선 뒤집기 *
  9. 메인 대각선 뒤집기 *

* 하위 행렬이 정사각형 인 경우에만

물론, 그는 전체 매트릭스에서이 단계를 수행 할 수도 있습니다. 1과 0은 매트릭스에서만 교환 할 수 있지만 정사각형 값은 직접 변경할 수 없으므로 1과 0의 수는 시작 및 끝 구성에서 동일합니다.

포맷 사양 + 규칙

원하는 형식으로 입력을 두 개의 정사각 행렬 (시작 위치 및 끝 위치)로 제공합니다. 출력은 읽을 수있는 형식으로 이러한 단계의 순서 여야합니다. 이것은 코드 골프가 아니므로 쉽게 확인할 수있는 형식으로 만드십시오. 그러나 엄격한 요구 사항은 아닙니다. 원하는 경우 입력에서 행렬의 측면 길이를 가져 오도록 선택할 수 있습니다.

귀하의 프로그램은 내 컴퓨터에서 실행됩니다 (Linux Mint, 누군가 관심이 있으시면 요청에 따라 정확한 버전 정보가 제공됩니다 : P). 나는 명령 행에서 "enter"를 누른 시간과 명령이 종료됩니다.

테스트 사례

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. 전체 매트릭스를 가져옵니다. 각 열을 순환 시키십시오.
  2. 중간 두 열을 하위 행렬로 가져갑니다. 각 열을 아래로 순환시킵니다 .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. 전체 매트릭스를 가져옵니다. 각 열을 아래로 순환 시키십시오.
  2. 가운데 열을 가져 가라. 아래로 순환 시키십시오 2.
  3. 상위 2 개 행을 가져옵니다. 세로로 뒤집습니다.
  4. 맨 윗줄의 가장 오른쪽에있는 2 개의 요소를 가져옵니다. 그것들을 교환하십시오 (오른쪽 / 왼쪽으로 1 회전, 수평으로 뒤집기).
  5. 맨 윗줄의 가장 왼쪽에있는 2 개의 요소를 가져옵니다. 그것들을 교환하십시오.

더 효율적인 방법이있을 수 있지만 중요하지 않습니다. 당신이 비록 하나를 찾으면 의견에 자유롭게 지적하십시오 :)

테스트 케이스 판단

이 테스트 케이스는 제출을 판단하는 데 사용됩니다. 답변이 테스트 사례를 너무 많이 전문화한다고 생각되면 임의의 입력을 다시 선택하여 새 사례로 모든 답변을 다시 판단 할 권리가 있습니다. 테스트 케이스를 찾을 수 여기 가기 시작이고, 바닥이 원하는 구성이다.

답변이 너무 전문화되어 있다고 생각되면 다음 테스트 사례의 MD5는 3c1007ebd4ea7f0a2a1f0254af204eed입니다. (이것은 속임수의 비난에서 자신을 자유롭게하기 위해 지금 여기에 기록되었습니다 : P)

표준 허점이 적용됩니다. 응답이 없습니다. 행복한 코딩!

참고 : Advent Of Code 에서이 챌린지 시리즈에 대한 영감을 얻었습니다 . 이 사이트와 관련이 없습니다

여기서 첫 번째 도전 과제의 '링크 된'섹션을 보면 시리즈의 모든 도전 과제 목록을 볼 수 있습니다 .


정보 : 테스트 케이스에는 192 0및 64 1가 있으며 256 choose 64 ≈ 1.9 × 10⁶¹도달 가능한 총 행렬이 있습니다. (Megaminx와 비교할 수 있으며 교수의 큐브보다 훨씬 적지 만 Rubik의 복수보다 큼)
user202729

답변:


1

자바

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

약간 더 빠른 하드 코딩 된 버전 : 온라인으로 사용해보십시오!

입력은 명령 행을 통해 공백으로 구분 된 정수입니다. 첫 번째 정수는 두 행렬의 너비입니다. 나머지 정수는 행 단위의 요소입니다.

행렬의 모든 순열은 수평 플립 및 수직 플립 연산자로 얻을 수 있으므로 동일한 영역에서 연속 vFlip 및 hFlip을 180도 회전으로 바꾸는 것을 제외하고 나머지는 무시했습니다.

프로그램은 각 요소를 스캔합니다. 비트가 잘못된 요소가 발견 될 때마다 배열을 통해 앞뒤로보고 올바른 비트가있는 지점을 찾습니다. 검색 영역을 두 개로 나누었습니다. 열 좌표가 같거나 큰 열 좌표와 열 좌표가 작은 것입니다. 후자는 배열을 순회하는 방식에 따라 더 큰 행 좌표를 가져야합니다. 첫 번째 검색 영역에서 올바른 비트를 찾으면 두 요소에 걸쳐 하위 행렬을 180도 회전시켜 총 한 번의 작업을 수행 할 수 있습니다. 두 번째 영역에 있으면 수평 플립을 사용하여 올바른 비트를 잘못된 비트와 동일한 열로 이동 한 다음 하위 매트릭스를 두 개에 걸쳐 수직으로 뒤집어 총 2 개의 연산을 수행 할 수 있습니다.

프로그램의 결과물은 정신적으로 다섯 그룹으로 나누어 져야하는 배열입니다. 각 그룹은 (i, row1, col1, row2, col2)입니다. 여기서 i는 no-op의 경우 0, 180도 회전의 경우 1, 수평 플립의 경우 2, 수직 플립의 경우 3입니다. 나머지 4 개의 구성 요소는 작업이 실행되는 영역을 설명합니다. 이것이 읽을 수있는 형식인지 확실하지 않습니다.

주어진 테스트 사례에 대해 컴퓨터에서 258 개의 작업과 2 ~ 3 밀리 초를 얻습니다.


@ Outgolfer @Erik 지정되지 않았으며 하드 코딩으로 쉽게 판단 할 수 있습니다.
WhatToDo

명령 행에서 입력을 받도록 변경했습니다
WhatToDo

이 출력 형식은 충분히 합리적입니다. 배열에 1000 개의 숫자가 있지만 (200 작업?) 258은 어디에서 왔습니까? 이 결과를 읽는 방법에 대해 약간 혼란 스럽습니다 .P
HyperNeutrino

내가 그것을 실행할 때, 나는 1290의 길이를 얻습니다 (no-ops가 시작될 때까지), 이것은 작업 수의 5 배입니다. 258은 작업 수에 불과합니다.
WhatToDo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.