En yüksek çevre polyomino


14

Bu kod golf. Kazanan, en az bayt içeren geçerli koddur.


Meydan okuma

M ve N girişleri , dikdörtgen bir kareler ızgarasının genişliği ve yüksekliği göz önüne alındığında , aşağıdakileri karşılayan bir çokgen çıktı:

  • Çokgen kenarlar sadece kare kenarlardan oluşur: çapraz kenarlar yoktur - hepsi dikey veya yataydır.
  • Çokgenin delikleri yoktur: Çokgenin dışındaki her kareye, dikdörtgenin dış sınırındaki çokgenin dışındaki bir kareden başlayarak, çokgenin dışındaki kareler üzerinde dikey adımlar ile ulaşılabilir.
  • Çokgenin kendiliğinden kesişmesi yoktur: bir tepe noktasında toplanan kare kenarlardan en fazla 2 tanesi çokgen çevresinin bir parçası olabilir.
  • Çokgen bağlanır: Çokgendeki herhangi bir kareye, çokgenin içinde kalan dikey adımlar aracılığıyla çokgendeki diğer herhangi bir kareden erişilebilir olmalıdır.
  • Poligon mümkün olan en yüksek çevreye sahiptir: aşağıda gösterilen formüle göre.

Kodunuz 1 ile 255 arasında M ve N için çalışmalıdır .


Maksimum çevre için formül

Buradaki zorluk, maksimum çevreye sahip olan çokgenlerin en golfçülüğünü bulmak. Maksimum çevrenin kendisi her zaman aşağıdaki formülle tanımlanır:

Bu doğrudur çünkü maksimum çevre için her kare tepe noktası çevre üzerinde olmalıdır. Tek sayıda köşe için bu mümkün değildir ve elde edilebilecek en iyi nokta bir köşe daha azdır (çünkü çevre her zaman eşittir).


Çıktı

Şekli, satırsonu ayrılmış karakterlerden oluşan bir dize ( tam olarak M karakterden oluşan N satır ) olarak çıktı. Burada çokgenin dışındaki kareler için boşluk kullanıyorum ve çokgenin içindeki kareler için '#' kullanıyorum, ancak anlamları tüm girdiler için tutarlı olması koşuluyla, görsel olarak farklı iki karakter kullanabilirsiniz.

En fazla bir önde gelen yeni satır ve en fazla bir sondaki yeni satır ekleyebilirsiniz.

İsterseniz , tam olarak N karakterli M satırları çıkarabilir ve bazı girişler için M by N çıkışını ve diğerleri için N by M çıkışını seçebilirsiniz .


Örnekler

Bir delik nedeniyle geçersiz :

###
# #
###

Kavşak (çapraz olarak dokunma - çevre üzerinde 4 kare kenarı olan bir tepe noktası) ve bu arada bir delik nedeniyle geçersiz :

##
# #
###

Bağlantısının kesilmesi nedeniyle geçersiz :

#
# #
  #

Maksimum çevre için geçerli çokgen:

# #
# #
###

Kredi

Başlangıçta maksimum çevre değerinin ne kadar hızlı hesaplanabileceğini hafife aldım ve sadece bu değeri çıktı olarak isteyecektim. Keyifli N ve M için maksimum çevreyi nasıl çalıştıracaklarını açıklayan ve bunu birden fazla cevap sürecek bir zorluğa dönüştürmeye yardımcı olan sohbetteki harika yardımcı insanlar sayesinde ...

Özellikle:

Sparr , Zgarb , feersum , jimmy23013 .


Bu soruyu polyominos veya çokgenler kullanarak adlandırabilirim (her ikisi de geçerlidir). Kimsenin tercihi var mı? Aşağıdakiler hakkında yorum oylarıyla gösterebilirsiniz:
trichoplax

5
En yüksek çevre
polyomino

1
En yüksek çevre bağlı çokgen
trichoplax

Tam M karakterden oluşan N satır: belirli girişler için uygun bulursak iki giriş değerini değiştirebilir miyiz?
Level River St

3
@steveverrill Çıktı bölümünü düzenledim. Bu isteğinize uygun mu?
trichoplax

Yanıtlar:


4

CJam, 47 bayt

l~_2%{\}|_'#:H*@({N+1$(2md\HS+*H+\SH+R=*++}fR\;

Çevrimiçi deneyin

Açıklama:

l~      Get and convert input.
_2%     Calculate second value modulo 2.
{\}|    If value is even, swap the two inputs. This puts odd on top if one is odd.
_'#:H*  Create top row of all # signs. Also save away # character as shortcut for later.
@(      Pull number of rows to top, and decrement because first is done.
{       Start loop over rows.
N+      Add newline.
1$      Copy row length to top of stack.
(2md    Decrement, and calculate mod/div with 2.
\       Swap mod and div, will use div first.
HS+     "# "
*       Repeat it based on div 2 of row length.
H+      Add one more #.
\       Swap mod of earlier division to top.
SH+     " #"
R=      Pick space or # depending on even/odd row number.
*       Repeat 0 or 1 times depending on mod 2 of row length.
+       Add the possible extra character to line.
+       Add line to result.
}fR     End of for loop over lines.
\;      Remove row length from stack, leaving only result string.

Sonuç için iki ana durum vardır. Boyutlardan en az biri garip ise, desen düz bir "tırmık" tır. Örneğin, giriş için 7 6:

#######
# # # #
# # # #
# # # #
# # # #
# # # #

Her iki boyut da eşitse, her ikinci karenin "açık" olduğu fazladan bir sütun vardır. Örneğin, giriş için 8 6:

########
# # # # 
# # # ##
# # # # 
# # # ##
# # # # 

Şimdi, bu paternlerin problem tanımında verildiği gibi çevresel teorik maksimum (M + 1) * (N + 1)değere ulaştığını göstermek için, ilk paternin çevresini , ikincisinin de aynı değer eksi 1 olduğunu doğrulamamız gerekir .

İlk desen için, Mgarip bir boyutla çevre için var :

  1. M üst kenar için.
  2. 2 üst sıranın yan tarafında.
  3. (M - 1) / 2 dişler arasındaki boşluklar için.
  4. (M + 1) / 22 * (N - 1) + 1her biri çevre olan dişler .

Bu, aşağıdakilere kadar ekler:

M + 2 + (M - 1) / 2 + (M + 1) / 2 * (2 * (N - 1) + 1) =
M + 2 + (M - 1) / 2 + (M + 1) * (N - 1) + (M + 1) / 2 =
2 * M + 2 + (M + 1) * (N - 1) =
(M + 1) * 2 + (M + 1) * (N - 1) =
(M + 1) * (N + 1)

Her iki Ikinci durumda Mve Nhatta vardır, çevre gelen ekler:

  1. M üst kenar için.
  2. 2 üst sıranın yan tarafında.
  3. M / 2 üst satırdaki açık # için.
  4. M / 22 * (N - 1) + 1her biri düz dişler için çevre olan dişler.
  5. En sağdaki diş, 2 * (N / 2 - 1)jaggies için ekstra bir çevre parçasına sahiptir .

Bunları bir araya getirerek:

M + 2 + M / 2 + (M / 2) * (2 * (N - 1) + 1) + 2 * (N / 2 - 1) =
M + 2 + (M / 2) * (2 * (N - 1) + 2) + N - 2 =
M + M * N + N =
(M + 1) * (N + 1) - 1

Pürüzlü kısmı sola yerleştirerek birkaç bayt kaydedebileceğimi düşünüyorum. Biraz daha az yığın karıştırma gerektirmelidir. Ama uyku vakti ...
Reto Koradi

5

Ruby, Rev 1, 66

->(m,n){n.times{|i|puts ("#"*m**(1-i%2)).rjust(m,i>n-2?"# ":" ")}}

m1 veya m #'lerin yazdırılıp yazdırılmayacağına karar vermek için 0 o 1 gücüne yükseltmek için kullanılır .

>Bunun yerine son satırı test etmek için kullanılır ==.

Ne koyar sonra, ne de herhangi bir parantez boşluklardan kurtulamaz!

Ruby, Rev 0, 69

->(m,n){n.times{|i|puts ("#"*(i%2==0?m:1)).rjust(m,i==n-1?"# ":" ")}}

Bu anonim bir lambda fonksiyonudur. Şöyle kullanın:

f=->(m,n){n.times{|i|puts ("#"*(i%2==0?m:1)).rjust(m,i==n-1?"# ":" ")}}

M=gets.to_i
N=gets.to_i
f.call(M,N)

Sonunda, M ve N'nin değiştirilip değiştirilemeyeceğini sorduktan sonra ihtiyacım yoktu.


N tek için tipik çıkışlar. Biz silerseniz #sağ tarafta kendi başlarına, açıkça (N + 1) (M + 1) sahip olacaktır. Şekle katılmaları dahil edildiğinde 2 kare yatay çevre çıkarılır ve 2 kare dikey çevre eklenir, bu nedenle değişiklik olmaz.

Burada "#"*(i%2==0?m:1)M #sembollerine alternatif satırlar ve bir #sembol vermek için ifadeye güveniriz ve M karakterlerini sağa yaslarız.

5                        6
5                        5
#####                    ######
    #                         #
#####                    ######
    #                         #
#####                    ######

N çift için tipik çıkışlar. alt sıranın crenelasyonu nedeniyle dikey çevre eklenmesi ile karşılaştırıldığında, 5 6açıkça aynı çevre 6 5veya M + 1 = 6 artışına sahiptir 5 5. artı dikey çevrede (M + 1) -1 = 6 artış ile 6 6aynıdır 6 5. Böylece formüle uygundurlar.

5                        6
6                        6
#####                    ######
    #                         #
#####                    ######
    #                         #
#####                    ######
# # #                    # # ##

Ruby'nin rjustboş hücreler için kullanılacak dolguları belirtmenize izin vermesi çok kullanışlıdır . Normalde dolgu olarak ayarlanır, " "ancak son sıra için geçiş yaparız "# "(dolgu yalnızca N eşitse son satırda gerekli olacaktır. N'nin garip olduğu yerde son sıra tamamlanacak ve haklı olmayacaktır, bu nedenle çığlıkları görmeyecek.)

Buradan kontrol edin.


@ Vioz- ideone için teşekkürler! Kenar vakaları olup olmadığını görmek için programı düşük N ve M değerlerine kadar test ettim, ancak bu kadar yüksek değerler için işe yarayıp yaramayacağını kontrol etmedim. Görünüşe göre hem crenellation hem de crenelation doğru, bu yüzden bırakacağım. Bazı köşeli ayraçları ve boşlukları silebilir miyim görmek için daha sonra geri gelecek.
Level River St

Bağlantı için sorun değil mi? Test etmek için kullandığım için başkaları için yararlı olacağını düşündüm: P Yazım denetimi ile ilgili olarak, bulabildiğim ilk sonuca değiştirdim, çünkü aslında kullanılan kelimeyi hiç görmedim. Ben Ruby (hiçbir şey infact) hakkında pek bir şey bilmiyorum, ama sen değiştirebilir i%2==0için i%2<1(ben ideone bağlantısına bu değişikliği yaptık) bir bayt kaydedin.
Kade

#Hatta son sıra için dolguya gerçekten ihtiyacınız var mı? Örneğin, son şekilde, #sağ alt köşede olmadan çevre aynı değil mi?
Reto Koradi

@RetoKoradi gerçekten de aynı çevre olurdu - kod #zaten ekstra içeriyor gibi görünüyor çünkü zaten her satırın sonlandığı gibi, bu yüzden orada bir boşluk koymaktan daha az bayt. (Yakut bilmiyorum ama ...).
trichoplax

1
@trichoplax sezginiz doğru. Dolgu olduğu "# "değil " #"ikincisi 2 bitişik verecekti çünkü #kesinlikle istenmediği garip M için. 2 #bile M için bitişik zarar vermez, bu yüzden onunla gittim. Denemedim ljust, bununla daha temiz yapmak mümkün olabilir, ancak satır başına tam olarak M karakter bastığım o kadar açık olmazdı.
Level River St

5

C, 109 97 bayt ve doğruluk kanıtı

Çözümümü yazıyordum ama @steveverrill beni bununla dövdü. Aynı stratejiyi paylaşacağımı düşündüm, çünkü kullanılan strateji için bir doğruluk kanıtı ekledim.

İndirgenmiş Kod:

m,n,x;main(){for(scanf("%i%i",&m,&n); n;)putchar(x<m?"# "[x%2*(++x^m||~n&1)&&n^1]:(x=0,n--,10));}

İndirgeme Öncesi:

m,n,x;

main(){
    for(scanf("%i%i",&m,&n); n;) 

        /* If x == m, prints out a newline, and iterates outer 
         * loop (x=0,n--) using comma operator.
         * Otherwise, paints a '#' on :
         *     Every even column (when x%2 is 0)
         *     On odd columns of the last row (++x^m||~n&1 is 0)
         *     On the first row (when n^1 is 0)
         * And a ' ' on anything else (when predicate is 1) */
        putchar(x<m?"# "[x%2*(++x^m||~n&1)&&n^1]:(x=0,n--,10));
}

Strateji ve İspat:

Maksimum çevre denkleminin (M + 1) (N + 1) - ((M + 1) (N + 1)) mod 2'nin doğruluğunu varsayarsak, aşağıdakiler kullanılan en uygun stratejiyi açıklar ve indüksiyonla doğruluğunu kanıtlar:

Tek M için, M / 2 + 1 parmaklarla el benzeri bir şekil çiziyoruz, örneğin:

3x2
# # 
###

5x3
# # #
# # #
#####

Şimdi bu stratejinin tüm endüksiyonla tüm tek M için en uygun olduğunu kanıtlıyoruz:

Temel Durum: M = N = 1
Tek hücre dolu. (1 + 1) * (1 + 1) = 2 * 2 = 4 olduğundan ve karenin 4 tarafı olduğundan çözüm doğrudur.

Genişlikte indüksiyon:
El şekli stratejisinin M'nin tek olduğu (N, M-2) , yani çevresinin en uygun ve (N + 1) (M - 2 + 1) + ((M -1) (N + 1)) mod 2 . Şimdi (N, M) için çalışacağını gösteriyoruz .

Parmak ekleme işlemi, bir kenarı çokgenden kaldırır ve 3 + 2N ekler . Örneğin:

 5x3 -> 7x3
 # # # $
 # # # $
 #####$$

Bunu, bir önceki çevrenin optimal olduğu hipotezimizle birleştirdiğimizde, yeni çevre:

(N + 1)*(M - 2 + 1) - ((M+1)*(N+1)) mod 2 - 1 + 3 + 2*N
(N + 1)*(M + 1) - ((M-1)*(N+1)) mod 2 - 2(N + 1) - 1 + 3 + 2*N
(N + 1)*(M + 1) - ((M-1)*(N+1)) mod 2

Modulo 2 aritmetiği ile uğraştığımızdan,

((M-1)*(N+1)) mod 2 = ((M+1)*(N+1)) mod 2

Böylece, parmak ekleyerek genişliğin arttırılmasının en uygun çevreye yol açtığını kanıtlamak.

Yüksekliğine indüksiyonu:
el-biçimli stratejisinin işe yaradığını varsayalım (N-1, E) , E , kendi çevre uygun ve bir tek sayı olduğu N (M + 1) + ((M + 1) N) mod 2 . Şimdi (N, M) için çalışacağını gösteriyoruz .

Elin yüksekliğini artırmak sadece ilk ve diğer tüm x-endekslerinde bulunan parmakları uzatır. Her yükseklik artışı, her bir parmak çevresine iki ekler ve orada (M + 1) / 2 parmak, böylece, bir artış K bir artışa yol açar 2 (M + 1) / 2 = M + 1 içinde çevre.

Bunu hipotezle birleştirerek, yeni çevrenin:

N*(M + 1) + ((M+1)*N) mod 2 + M + 1
(N + 1)*(M + 1) + ((M+1)*N) mod 2

Modüler aritmetik, son terimi basitleştirmemize izin verir, böylece şunları elde ederiz:

(N + 1)*(M + 1) + ((M+1)*(N+1)) mod 2

Çözeltinin tüm N> 0 ve tek M> 0 için en uygun olduğunu kanıtlamak.

M için bile, tahtaya tek M için yaptığımız gibi doldururuz, ancak son segmente crenelasyonlar ekleriz, örneğin:

4x3
# ##
# # 
####

6x4
# # #
# # ##
# # #
######

Şimdi bu stratejinin en uygun olduğunu kanıtlıyoruz.

Eşit M için indüksiyon:
Çözeltinin (N, M-1) için doğru olduğunu ve (N + 1) M'nin optimal çevresine sahip tek M-1 (son durumda kanıtlandığı gibi) ile doğru olduğunu varsayın. M (N + 1)) mod 2 . Şimdi (N, M) için çalışacağını gösteriyoruz.

Parmakları arttırmak gibi, her bir crenlasyon çokgenin çevresine iki tane ekler. Toplam külasyon sayısı (N + N mod 2) / 2'dir , toplam N + N mod 2 çevre eklenmiştir.

Bunu hipotezle birleştirerek, yeni çevrenin:

(N + 1)*M - (M*(N+1)) mod 2 + N + N mod 2
(N + 1)*(M + 1) - (M*(N+1)) mod 2 + N mod 2 - 1
(N + 1)*(M + 1) - (M*(N+1)) mod 2 - (N + 1) mod 2

Bizde var

(M*(N+1)) mod 2 - (N + 1) mod 2 = ((M+1)*(N+1)) mod 2

Çünkü N tuhafsa, bu 0 = 0'a düşer ve N eşitse,

- A mod 2 - 1 = -(A + 1) mod 2

Dolayısıyla strateji tüm M, N> 0 için en uygunudur .


2
Bu çok fazla matematik! Oluşturduğunuz şeklin çevresini hesaplayıp, verilen maksimum değerle eşleştiğini gösteremez misiniz? Kaç parmağınız olduğunu, her parmağınızın ne kadar uzun olduğunu vb. Biliyorsunuz. Bu yüzden çevreyi hesaplamak oldukça kolay olmalı.
Reto Koradi

Doğru. Bazı açılardan, indüksiyon yolunun daha sezgisel olduğunu hissediyorum, çünkü katkı maddesi, ancak evet, daha uzun bir açıklamaya yol açıyor.
André Harder

Çevrenin geçtiği tam sayı noktalarının sayısına eşit olduğunu bilmek isteyebilirsiniz.
jimmy23013
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.