Thử thách Mùa Vọng 1: Giúp Santa mở khóa kho tiền hiện tại của mình!


18

Tiếp theo >>

Từ khóa mô tả (để tìm kiếm): Tạo hai ma trận tương đương, chồng chéo, mảng, tìm

Thử thách

Santa đã có một lịch sử yêu tinh ăn cắp quà từ kho tiền của anh ta trong quá khứ, vì vậy năm nay anh ta đã thiết kế một khóa rất khó để bẻ khóa, và dường như nó đã giữ các yêu tinh trong năm nay. Thật không may, anh ta đã mất kết hợp và anh ta cũng không thể tìm ra cách mở nó! May mắn thay, anh ấy đã thuê bạn viết một chương trình để tìm sự kết hợp. Nó không cần phải là cái ngắn nhất, nhưng anh ta cần tìm nó càng nhanh càng tốt!

Anh ấy có một lịch trình rất nghiêm ngặt và anh ấy không thể chờ đợi lâu. Điểm của bạn sẽ là tổng thời gian chạy của chương trình của bạn nhân với số bước mà chương trình của bạn đưa ra cho đầu vào tính điểm. Điểm số thấp nhất chiến thắng.

Thông số kỹ thuật

Khóa là một ma trận vuông 1s và 0. Nó được đặt thành một sự sắp xếp ngẫu nhiên 1 và 0 và cần được đặt thành một mã được chỉ định. May mắn thay, Santa nhớ mã yêu cầu.

Có một vài bước anh ta có thể thực hiện. Mỗi bước có thể được thực hiện trên bất kỳ ma trận con liền kề nào (nghĩa là bạn phải chọn một ma trận con được giới hạn hoàn toàn bởi một góc trên cùng bên trái và dưới cùng bên phải) (có thể là ma trận con không vuông):

  1. Xoay phải 90 độ *
  2. Xoay trái 90 độ *
  3. Xoay 180 độ
  4. Chu kỳ mỗi nphần tử hàng phải hoặc trái (kết thúc tốt đẹp)
  5. Chu kỳ mỗi mphần tử cột lên hoặc xuống (kết thúc tốt đẹp)
  6. Lật theo chiều ngang
  7. Lật theo chiều dọc
  8. Lật trên đường chéo chính *
  9. Lật trên đường chéo chính *

* chỉ khi ma trận con là hình vuông

Tất nhiên, anh ta cũng có thể thực hiện các bước này trên toàn bộ ma trận. Vì 1 và 0 chỉ có thể được hoán đổi trên ma trận nhưng giá trị của hình vuông không thể thay đổi trực tiếp, nên số 1 và 0 là giống nhau cho cấu hình bắt đầu và kết thúc.

Định dạng thông số kỹ thuật + Quy tắc

Bạn sẽ được cung cấp đầu vào dưới dạng hai ma trận vuông (vị trí bắt đầu và vị trí kết thúc) theo bất kỳ định dạng hợp lý nào bạn muốn. Đầu ra phải là một chuỗi các bước này ở bất kỳ định dạng nào có thể đọc được. Vì đây không phải là môn đánh gôn, vui lòng biến nó thành một định dạng dễ kiểm chứng, nhưng đó không phải là một yêu cầu nghiêm ngặt. Bạn có thể chọn lấy độ dài cạnh của ma trận trong đầu vào nếu bạn muốn.

Chương trình của bạn sẽ được chạy trên máy tính của tôi (Linux Mint, chi tiết phiên bản chính xác có sẵn theo yêu cầu nếu có ai quan tâm: P) và tôi sẽ tính thời gian dựa trên khoảng thời gian giữa lúc tôi nhấn "enter" trên dòng lệnh và khi lệnh thoát.

Các trường hợp thử nghiệm

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. Lấy toàn bộ ma trận. Chu kỳ mỗi cột lên 1.
  2. Lấy hai cột giữa làm ma trận phụ. Chu kỳ mỗi cột xuống 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. Lấy toàn bộ ma trận. Chu kỳ mỗi cột xuống 1.
  2. Lấy cột giữa. Chu kỳ xuống 2.
  3. Lấy 2 hàng trên cùng. Lật nó theo chiều dọc.
  4. Lấy 2 yếu tố trên cùng bên phải của hàng trên cùng. Hoán đổi chúng (xoay phải / trái 1, lật theo chiều ngang).
  5. Lấy 2 yếu tố ngoài cùng bên trái của hàng trên cùng. Trao đổi chúng.

Có thể có các phương pháp hiệu quả hơn, nhưng điều đó không thành vấn đề. Vui lòng chỉ ra chúng trong các ý kiến ​​nếu bạn tìm thấy một mặc dù :)

Đánh giá vụ án

Trường hợp thử nghiệm này sẽ được sử dụng để đánh giá trình của bạn. Nếu tôi tin rằng một câu trả lời dành riêng cho trường hợp thử nghiệm quá nhiều, tôi có quyền lặp lại một đầu vào ngẫu nhiên và từ chối tất cả các câu trả lời với trường hợp mới. Trường hợp thử nghiệm có thể được tìm thấy ở đây , nơi trên cùng là bắt đầu và dưới cùng là cấu hình mong muốn.

Nếu tôi tin rằng câu trả lời là chuyên môn quá nhiều, MD5 của trường hợp thử nghiệm tiếp theo là 3c1007ebd4ea7f0a2a1f0254af204eed. (Điều này được viết ở đây ngay bây giờ để giải phóng bản thân khỏi những lời buộc tội gian lận: P)

Áp dụng sơ hở tiêu chuẩn. Không có câu trả lời sẽ được chấp nhận. Chúc mừng mã hóa!

Lưu ý: Tôi đã lấy cảm hứng cho loạt thử thách này từ Advent Of Code . Tôi không có liên kết với trang web này

Bạn có thể xem danh sách tất cả các thử thách trong chuỗi bằng cách xem phần 'Liên kết' của thử thách đầu tiên tại đây .


Thông tin: Trường hợp thử nghiệm có 192 0và 64 1, và có tổng số 256 choose 64 ≈ 1.9 × 10⁶¹ma trận có thể tiếp cận. (có thể so sánh với Megaminx và lớn hơn Rubik's Revenge, mặc dù ít hơn nhiều so với khối của Giáo sư)
user202729

Câu trả lời:


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

Phiên bản mã hóa cứng nhanh hơn một chút: Hãy thử trực tuyến!

Đầu vào là không gian được phân tách bằng số nguyên thông qua dòng lệnh. Số nguyên đầu tiên là chiều rộng của hai ma trận. Các số nguyên còn lại là các phần tử của chúng, từng hàng.

Mọi hoán vị của một ma trận có thể thu được chỉ bằng các toán tử lật ngang và lật dọc, vì vậy tôi bỏ qua phần còn lại ngoại trừ việc thay thế một vFlip và hFlip liên tiếp trong cùng khu vực với góc quay 180 độ.

Chương trình quét qua từng yếu tố. Bất cứ khi nào chúng ta gặp một phần tử có bit sai, nó sẽ nhìn xa hơn về phía trước qua mảng để tìm một điểm có bit chính xác. Tôi đã chia khu vực tìm kiếm thành hai: những khu vực có tọa độ cột bằng hoặc lớn hơn và những khu vực có tọa độ cột nhỏ hơn. Lưu ý rằng cái sau phải có tọa độ hàng lớn hơn dựa trên cách chúng ta đi ngang qua mảng. Nếu chúng ta tìm thấy một bit chính xác trong vùng tìm kiếm đầu tiên, chúng ta có thể xoay 180 độ ma trận con bao trùm hai phần tử cho tổng số một thao tác. Nếu nó ở khu vực thứ hai, chúng ta có thể sử dụng lật ngang để di chuyển bit chính xác sang cùng một cột với bit sai và sau đó lật theo chiều dọc ma trận con kéo dài cả hai cho tổng số hai thao tác.

Đầu ra của chương trình là một mảng nên được chia thành các nhóm năm. Mỗi nhóm là (i, row1, col1, row2, col2) trong đó i là 0 cho một no-op, 1 cho xoay 180 độ, 2 cho lật ngang và 3 cho lật dọc. 4 thành phần còn lại mô tả khu vực mà hoạt động chạy. Tôi không chắc chắn nếu đây là một định dạng có thể đọc được.

Đối với trường hợp thử nghiệm đã cho, tôi nhận được 258 thao tác và hai đến ba mili giây trên máy tính của mình.


@Erik the Outgolfer Nó không được chỉ định và mã hóa cứng giúp cho việc đánh giá dễ dàng hơn.
WhatToDo

Tôi đã thay đổi nó để lấy đầu vào từ dòng lệnh
WhatToDo

Định dạng đầu ra này là đủ hợp lý. Tôi đang nhận được 1000 số trong mảng (200 thao tác?) Vậy số 258 đến từ đâu? Tôi hơi bối rối về cách đọc đầu ra từ đây: P
HyperNeutrino

Khi tôi chạy nó, tôi nhận được độ dài 1290 (cho đến khi no-op bắt đầu), gấp năm lần số lượng hoạt động. Số 258 chỉ là số lượng hoạt động.
WhatToDo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.