Advent Challenge 1: Допоможіть Санта розблокувати свій теперішній сейф!


18

Далі >>

Описові ключові слова (для пошуку): Зробіть дві матриці еквівалентними, перекриттями, масивом, знайдіть

Виклик

У Санта в минулому була історія, коли ельфи крали подарунки зі свого сховища, тому в цьому році він сконструював замок, який дуже важко зламати, і, схоже, в цьому році ельфів утримав. На жаль, він втратив комбінацію, і він не може зрозуміти, як її відкрити! На щастя, він найняв вас написати програму, щоб знайти комбінацію. Він не повинен бути найкоротшим, але він повинен знайти його якомога швидше!

У нього дуже суворий графік, і він не може дозволити собі довго чекати. Вашим балом буде загальний час роботи вашої програми, помножене на кількість кроків, які ваша програма виводить для введення оцінки. Виграє найнижчий рахунок.

Технічні умови

Замок - це квадратна матриця 1s і 0s. Він встановлений у випадковому розташуванні 1s і 0s і його потрібно встановити у визначеному коді. На щастя, Санта запам’ятовує необхідний код.

Є кілька кроків, які він може виконати. Кожен крок може бути виконаний на будь-якій суміжній підматриці (тобто виберіть підматрицю, яка повністю обмежена вгорі-лівому та правому нижньому куті) (це може бути неквадратна підматриця):

  1. Поворот праворуч на 90 градусів *
  2. Поворот ліворуч на 90 градусів *
  3. Поворот на 180 градусів
  4. Обведіть усі nелементи рядка праворуч або ліворуч (обгортання)
  5. Циклічні mелементи кожного стовпчика вгору або вниз (обгортання)
  6. Переверніть горизонтально
  7. Переверніть вертикально
  8. Переверніть головну діагональ *
  9. Переверніть головну протидіагональну *

* тільки якщо підматриця квадратна

Звичайно, він також може виконати ці дії на всій матриці. Оскільки 1s і 0s можна заміняти лише на матриці, але значення квадрата неможливо змінити безпосередньо, число 1s і 0s є однаковим для конфігурації початку і кінця.

Специфікації форматування + правила

Ви отримаєте вхід у вигляді двох квадратних матриць (вихідна позиція та кінцева позиція) у будь-якому потрібному форматі. Вихід повинен бути послідовністю цих кроків у будь-якому читаному форматі. Оскільки це не код-гольф, будь ласка, зробіть його легко перевіряемим форматом, але це не сувора вимога. При бажанні ви можете взяти бічну довжину матриць на вході.

Ваша програма буде запускатися на моєму комп’ютері (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. Візьміть всю матрицю. Обведіть кожен стовпець вгору 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. Візьміть всю матрицю. Обведіть кожен стовпчик вниз по 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 і більше, ніж помста Рубіка, хоча набагато менше куба професора)
user202729

Відповіді:


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

Трохи швидша версія жорсткого коду: Спробуйте в Інтернеті!

Введення - це цілі числа, розділені пробілом, через командний рядок. Перше ціле число - ширина двох матриць. Решта цілих чисел - це їх елементи, рядки за рядком.

Кожна перестановка матриці може бути отримана лише за допомогою операторів горизонтального фліпу та вертикального відкидання, тому я проігнорував решту, окрім заміни послідовних vFlip та hFlip у тому ж регіоні з обертанням на 180 градусів.

Програма сканує кожен елемент. Щоразу, коли ми стикаємося з елементом, який має неправильний біт, він дивиться далі вперед через масив, щоб знайти місце, яке має правильний біт. Я розділив область пошуку на дві частини: ті, що мають рівну або більшу координату стовпців, і ті, що мають меншу координату стовпців. Зауважте, що останній повинен мати більшу координату рядків на основі того, як ми мандруємо масивом. Якщо ми знайдемо правильний біт у першій області пошуку, ми можемо просто повернути на 180 градусів субматрицю, що охоплює два елементи, загалом за одну операцію. Якщо він знаходиться у другій області, ми можемо використовувати горизонтальний фліп, щоб перемістити правильний біт у той самий стовпець, що і неправильний біт, а потім вертикально перевернути підматрицю, що охоплює два, в цілому дві операції.

Вихід програми - це масив, який слід подумки розділити на п'ять груп. Кожна група - це (i, рядок1, col1, рядок2, col2), де i дорівнює 0 для неоперації, 1 для повороту на 180 градусів, 2 для горизонтального перевороту і 3 для вертикального перевороту. Решта 4 компоненти описують область, над якою працює операція. Я не впевнений, чи це читабельний формат.

Для даного тестового випадку я отримую 258 операцій і дві-три мілісекунди на своєму комп’ютері.


@Erik the Outgolfer Це не було зазначено, а жорстке кодування полегшує судження.
WhatToDo

Я змінив його, щоб взяти вхід з командного рядка
WhatToDo

Цей вихідний формат досить розумний. Я отримую 1000 чисел у масиві, хоча (200 операцій?), Тож звідки 258? Я трохи розгублений, як читати вихід із цього: P
HyperNeutrino

Коли я запускаю його, я отримую довжину 1290 (до запуску без операцій), що в п'ять разів перевищує кількість операцій. 258 - це лише кількість операцій.
WhatToDo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.