Advent Challenge 1: Santa'nın mevcut kasasının kilidini açmasına yardım et!


18

Sonraki >>

Açıklayıcı Anahtar Kelimeler (arama için): İki Matrisi Eşdeğer Yap, Çakışma, Dizi, Bul

Meydan okuma

Santa geçmişte kasasından hediye çalmak için elflerin bir geçmişine sahipti, bu yüzden bu yıl kırılması çok zor bir kilit tasarladı ve bu yıl elfleri dışarıda tutmuş gibi görünüyor. Ne yazık ki, kombinasyonu kaybetti ve nasıl açılacağını da anlayamıyor! Neyse ki, kombinasyonu bulmak için bir program yazmanız için sizi işe aldı. En kısa olanı olması gerekmez, ancak mümkün olduğunca hızlı bulması gerekir!

Çok katı bir programı var ve çok uzun süre bekleyemez. Skorunuz, programınızın toplam çalışma süresinin, puanlama girişi için program çıktılarınızın sayısıyla çarpımı olacaktır. En düşük puan kazanır.

Özellikler

Kilit, 1s ve 0s kare bir matristir. 1s ve 0s arasında rastgele bir düzenlemeye ayarlanmıştır ve belirtilen bir koda ayarlanması gerekir. Neyse ki, Santa gerekli kodu hatırlıyor.

Gerçekleştirebileceği birkaç adım var. Her adım herhangi bir bitişik alt matris üzerinde gerçekleştirilebilir (yani, tamamen sol üst ve sağ alt köşeyle sınırlanmış bir alt matris seçmelisiniz) (kare olmayan bir alt matris olabilir):

  1. 90 derece sağa döndür *
  2. 90 derece sola döndür *
  3. 180 derece döndür
  4. Her satır nöğesini sağa veya sola döndürme (tamamlama)
  5. Her sütun möğesini yukarı veya aşağı döngü (sarma)
  6. Yatay olarak çevir
  7. Dikey Çevir
  8. Ana Köşeyi Çevir *
  9. Ana Anti-diyagonal üzerinde kapak *

* sadece alt matris kare ise

Tabii ki, bu adımları tüm matris üzerinde de gerçekleştirebilir. 1s ve 0s yalnızca matriste değiştirilebilir, ancak bir karenin değeri doğrudan değiştirilemediğinden, 1s ve 0s sayısı başlangıç ​​ve bitiş yapılandırması için aynıdır.

Biçimlendirme Spesifikasyonları + Kurallar

Girişe istediğiniz makul formatta iki kare matris (başlangıç ​​konumu ve bitiş konumu) verilecektir. Çıktı, okunabilir herhangi bir biçimde bu adımların bir sırası olmalıdır. Bu kod golf olmadığından, lütfen kolayca doğrulanabilir bir biçim yapın, ancak bu kesin bir gereklilik değildir. İsterseniz girişteki matrislerin yan uzunluğunu almayı seçebilirsiniz.

Programınız bilgisayarımda çalıştırılacaktır (Linux Mint, herhangi biri umursuyorsa istek üzerine kesin sürüm ayrıntıları mevcuttur: P) ve komut satırında "enter" tuşuna bastığım zaman ile komut çıkışları.

Test Durumları

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. Tüm matrisi alın. Her sütunu yukarı doğru döndür 1.
  2. Ortadaki iki sütunu bir alt matris olarak alın. Her sütunu aşağı doğru döndürün 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. Tüm matrisi alın. Her sütunu aşağı doğru döndür 1.
  2. Orta sütunu al. Aşağıya doğru çevirin 2.
  3. En üstteki 2 satırı alın. Dikey olarak çevirin.
  4. En üst sıradaki en sağdaki 2 elemanı ele alalım. Değiştirin (sağa / sola 1 döndürün, yatay olarak çevirin).
  5. En üst satırın en soldaki 2 öğesini alın. Onları değiştirin.

Daha etkili yöntemler olabilir, ama bu önemli değil. Eğer bir tane bulursanız onları yorumlarda belirtmekten çekinmeyin :)

Yargılama Testi Örneği

Bu test örneği, başvurunuzu değerlendirmek için kullanılacaktır. Bir cevabın test senaryosu için çok fazla uzmanlaştığına inanıyorsam, rastgele bir girişi tekrarlama ve yeni vaka ile tüm cevapları reddetme hakkım var. Test durumu bulunabilir burada üst başlangıçtır ve alt istenen yapılandırma nerede.

Yanıtların çok fazla uzmanlaştığına inanıyorsam, bir sonraki test vakasının MD5'i 3c1007ebd4ea7f0a2a1f0254af204eed. (Bu şu anda kendimi hile suçlamalarından kurtarmak için yazılmıştır: P)

Standart Loopholes Uygula. Hiçbir cevap kabul edilmeyecektir. Mutlu kodlama!

Not: Advent Of Code'dan bu meydan okuma serisi için ilham aldım . Bu siteyle hiçbir bağlantım yok

Buradaki ilk zorluğun 'Bağlantılı' bölümüne bakarak dizideki tüm zorlukların bir listesini görebilirsiniz .


Bilgi: Test durumu 192 0ve 64'lere sahiptir 1ve toplam 256 choose 64 ≈ 1.9 × 10⁶¹ulaşılabilir matrisler vardır. (bu bir Megaminx ile karşılaştırılabilir ve bir Profesörün küpünden çok daha az olmasına rağmen bir Rubik İntikamından daha büyüktür)
user202729

Yanıtlar:


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

Biraz daha hızlı sabit kodlanmış sürüm: Çevrimiçi deneyin!

Giriş, komut satırı üzerinden boşlukla ayrılmış tamsayılardır. İlk tam sayı, iki matrisin genişliğidir. Kalan tamsayılar satır satır öğeleri.

Bir matrisin her permütasyonu sadece yatay çevirme ve dikey çevirme operatörleri ile elde edilebilir, bu yüzden aynı bölgedeki ardışık bir vFlip ve hFlip'i 180 derece döndürmeyle değiştirmek dışında kalanları görmezden geldim.

Program her öğeyi tarar. Yanlış biti olan bir elemanla karşılaştığımızda, doğru biti olan bir nokta bulmak için dizi boyunca daha ileriye bakar. Arama bölgesini ikiye böldüm: eşit veya daha büyük sütun koordinatına sahip olanlar ve daha küçük sütun koordinatına sahip olanlar. İkincisinin diziyi geçme şeklimize bağlı olarak daha büyük bir satır koordinatına sahip olması gerektiğini unutmayın. İlk arama bölgesinde doğru bir bit bulursak, toplam bir işlem için iki öğeyi kapsayan alt matrisi 180 derece döndürebiliriz. İkinci bölgede ise, doğru biti yanlış bitle aynı sütuna taşımak için yatay bir kapak kullanabilir ve ardından toplam iki işlem için ikiyi kapsayan alt matrisi dikey olarak çevirebiliriz.

Programın çıktısı zihinsel olarak beşli gruplara bölünmesi gereken bir dizidir. Her grup (i, satır1, sütun1, satır2, sütun2'dir) burada i no-op için 0, 180 derece döndürme için 1, yatay çevirme için 2 ve dikey çevirme için 3'tür. Kalan 4 bileşen, işlemin çalıştığı bölgeyi tanımlar. Bunun okunabilir bir biçim olup olmadığından emin değilim.

Verilen test durumunda, bilgisayarımda 258 işlem ve iki ila üç milisaniye alıyorum.


@ Outgolfer'ı belirtin Belirtilmedi ve sert kodlanması yargılamayı kolaylaştırıyor.
WhatToDo

Komut satırından girdi almak için değiştirdim
WhatToDo

Bu çıktı biçimi yeterince makul. Ben olsa dizi (200 işlemleri?) 1000 numaraları alıyorum yani 258 nereden geliyor? Bu çıktıyı nasıl okuyacağım konusunda biraz kafam karıştı: P
HyperNeutrino

Çalıştırdığımda, operasyon sayısının beş katı olan 1290 (ops ops başlayana kadar) bir uzunluk elde ederim. 258 sadece operasyon sayısıdır.
WhatToDo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.