Advent Challenge 1: Bantu Santa membuka brankasnya sekarang!


18

Selanjutnya >>

Kata Kunci Deskriptif (untuk pencarian): Membuat Dua Matriks Setara, Tumpang tindih, Array, Temukan

Tantangan

Santa memiliki sejarah elf mencuri hadiah dari brankasnya di masa lalu, jadi tahun ini dia merancang kunci yang sangat sulit untuk dipecahkan, dan tampaknya telah membuat elf keluar tahun ini. Sayangnya, dia telah kehilangan kombinasinya dan dia juga tidak tahu cara membukanya! Untungnya, dia telah mempekerjakan Anda untuk menulis sebuah program untuk menemukan kombinasi. Itu tidak harus menjadi yang terpendek, tetapi ia harus menemukannya secepat mungkin!

Dia memiliki jadwal yang sangat ketat dan dia tidak bisa menunggu terlalu lama. Skor Anda akan menjadi total run-time program Anda dikalikan dengan jumlah langkah output program Anda untuk input skor. Skor terendah menang.

Spesifikasi

Kunci adalah matriks kuadrat dari 1s dan 0s. Ini diatur ke pengaturan acak 1s dan 0s dan perlu diatur ke kode yang ditentukan. Untungnya, Santa mengingat kode yang diperlukan.

Ada beberapa langkah yang bisa dia lakukan. Setiap langkah dapat dilakukan pada setiap sub-matriks yang berdekatan (yaitu, Anda harus memilih sub-matriks yang sepenuhnya dibatasi oleh sudut kiri atas dan kanan bawah) (ini dapat berupa sub-matriks non-persegi):

  1. Putar ke kanan 90 derajat *
  2. Putar ke kiri 90 derajat *
  3. Putar 180 derajat
  4. Siklus setiap nelemen baris ke kanan atau kiri (membungkus)
  5. Siklus setiap melemen kolom ke atas atau bawah (membungkus)
  6. Balik secara Horizontal
  7. Balik secara Vertikal
  8. Balik di Diagonal Utama *
  9. Balik di Anti-diagonal Utama *

* hanya jika sub-matriksnya persegi

Tentu saja, ia juga dapat melakukan langkah-langkah ini pada seluruh matriks. Karena 1s dan 0s hanya dapat ditukar pada matriks tetapi nilai kuadrat tidak dapat secara langsung diubah, jumlah 1s dan 0s adalah sama untuk konfigurasi awal dan akhir.

Memformat Spesifikasi + Aturan

Anda akan diberikan input sebagai dua matriks persegi (posisi awal dan posisi akhir) dalam format wajar apa pun yang Anda inginkan. Output harus berupa urutan langkah-langkah ini dalam format apa pun yang dapat dibaca. Karena ini bukan kode-golf, harap buat format yang mudah diverifikasi, tetapi itu bukan persyaratan yang ketat. Anda dapat memilih untuk mengambil panjang sisi matriks dalam input jika Anda mau.

Program Anda akan dijalankan di komputer saya (Linux Mint, detail versi yang pasti tersedia atas permintaan jika ada yang peduli: P) dan saya akan menentukan waktu berdasarkan jumlah waktu antara waktu saya menekan "enter" pada baris perintah dan ketika perintah keluar.

Uji Kasus

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. Ambil seluruh matriks. Siklus setiap kolom ke atas 1.
  2. Ambil dua kolom tengah sebagai sub-matriks. Turunkan setiap kolom 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. Ambil seluruh matriks. Turunkan setiap kolom ke bawah 1.
  2. Ambil kolom tengah. Siklus ke bawah 2.
  3. Ambil 2 baris teratas. Balikkan secara vertikal.
  4. Ambil 2 elemen paling kanan baris paling atas. Tukar mereka (putar kanan / kiri 1, balik secara horizontal).
  5. Ambil 2 elemen paling kiri baris paling atas. Tukar mereka.

Mungkin ada metode yang lebih efisien, tetapi itu tidak masalah. Jangan ragu untuk menunjukkannya di komentar jika Anda menemukannya :)

Menilai Kasus Uji

Kasing uji ini akan digunakan untuk menilai kiriman Anda. Jika saya percaya bahwa suatu jawaban khusus untuk kasus uji terlalu banyak, saya memiliki hak untuk mengambil kembali input acak dan menilai kembali semua jawaban dengan kasus baru. Kasing uji dapat ditemukan di sini di mana bagian atas adalah awal dan bagian bawah adalah konfigurasi yang diinginkan.

Jika saya yakin jawaban terlalu khusus, MD5 untuk test case berikutnya adalah 3c1007ebd4ea7f0a2a1f0254af204eed. (Ini ditulis di sini sekarang untuk membebaskan diri dari tuduhan kecurangan: P)

Celah Standar Berlaku. Tidak ada jawaban yang akan diterima. Selamat coding!

Catatan: Saya mendapat inspirasi untuk seri tantangan ini dari Advent Of Code . Saya tidak memiliki afiliasi dengan situs ini

Anda dapat melihat daftar semua tantangan dalam seri ini dengan melihat bagian 'Tertaut' dari tantangan pertama di sini .


Informasi: Kasing uji memiliki 192 0dan 64 1, dan ada total 256 choose 64 ≈ 1.9 × 10⁶¹matriks yang dapat dijangkau. (yang sebanding dengan Megaminx, dan lebih besar dari Pembalasan Rubik, meskipun jauh lebih sedikit dari kubus Profesor)
user202729

Jawaban:


1

Jawa

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

Versi hard-coded yang sedikit lebih cepat: Cobalah secara online!

Input adalah integer yang dipisahkan ruang melalui baris perintah. Bilangan bulat pertama adalah lebar dari dua matriks. Bilangan bulat yang tersisa adalah elemen mereka, baris demi baris.

Setiap permutasi dari suatu matriks dapat diperoleh hanya dengan operator flip horizontal dan flip vertikal, jadi saya mengabaikan sisanya kecuali untuk mengganti vFlip dan hFlip berturut-turut di wilayah yang sama dengan rotasi 180 derajat.

Program memindai melalui setiap elemen. Setiap kali kita menemukan elemen yang memiliki bit yang salah, itu melihat lebih jauh ke depan melalui array untuk menemukan tempat yang memiliki bit yang benar. Saya telah membagi wilayah pencarian menjadi dua: area dengan koordinat kolom yang sama atau lebih besar, dan area dengan koordinat kolom yang lebih kecil. Perhatikan bahwa yang terakhir harus memiliki koordinat baris yang lebih besar berdasarkan cara kita melintasi array. Jika kami menemukan bit yang benar di wilayah pencarian pertama, kami hanya dapat memutar 180 derajat sub-matriks yang mencakup dua elemen untuk total satu operasi. Jika berada di wilayah kedua, kita dapat menggunakan flip horizontal untuk memindahkan bit yang benar ke kolom yang sama dengan bit yang salah dan kemudian secara vertikal membalikkan sub-matriks yang membentang keduanya untuk total dua operasi.

Output dari program ini adalah sebuah array yang harus dibagi secara mental menjadi lima kelompok. Setiap kelompok adalah (i, row1, col1, row2, col2) di mana saya adalah 0 untuk no-op, 1 untuk rotasi 180 derajat, 2 untuk flip horizontal, dan 3 untuk flip vertikal. Sisa 4 komponen menggambarkan wilayah pengoperasian. Saya tidak yakin apakah ini format yang bisa dibaca.

Untuk kasus uji yang diberikan, saya mendapatkan 258 operasi dan dua hingga tiga milidetik di komputer saya.


@Erik the Outgolfer Itu tidak ditentukan, dan hard-coding membuatnya lebih mudah untuk menilai.
WhatToDo

Saya telah mengubahnya untuk mengambil input dari baris perintah
WhatToDo

Format output ini cukup masuk akal. Saya mendapatkan 1000 angka dalam array (200 operasi?) Jadi dari mana 258 berasal? Saya sedikit bingung bagaimana cara membaca output dari ini: P
HyperNeutrino

Ketika saya menjalankannya, saya mendapatkan panjang 1290 (sampai no-ops mulai), yang merupakan lima kali jumlah operasi. 258 hanyalah jumlah operasi.
WhatToDo
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.