Polyomino chu vi cao nhất


14

Đây là mã golf. Người chiến thắng là mã hợp lệ với số byte nhỏ nhất.


Thử thách

Cho đầu vào MN , chiều rộng và chiều cao của một ô vuông hình chữ nhật, xuất ra một đa giác thỏa mãn các điều sau:

  • Các cạnh đa giác chỉ được tạo thành từ các cạnh vuông: không có cạnh chéo - tất cả đều là dọc hoặc ngang.
  • Đa giác không có lỗ: mọi hình vuông bên ngoài đa giác có thể đạt được bằng các bước trực giao trên các hình vuông bên ngoài đa giác, bắt đầu từ một hình vuông bên ngoài đa giác trên ranh giới bên ngoài của hình chữ nhật.
  • Đa giác không có giao điểm tự: của các cạnh vuông gặp nhau ở một đỉnh, không quá 2 có thể là một phần của chu vi đa giác.
  • Đa giác được kết nối: bất kỳ hình vuông nào trong đa giác đều có thể truy cập được từ bất kỳ hình vuông nào khác trong đa giác thông qua các bước trực giao nằm trong đa giác.
  • Đa giác có chu vi tối đa có thể: theo công thức hiển thị bên dưới.

Mã của bạn phải hoạt động cho MN từ 1 đến 255.


Công thức cho chu vi tối đa

Thách thức ở đây là tìm ra nhiều golf nhất trong số các đa giác với chu vi tối đa. Bản thân chu vi tối đa luôn được xác định bởi công thức:

Điều này đúng bởi vì đối với chu vi tối đa, mỗi đỉnh vuông phải nằm trên chu vi. Đối với một số đỉnh lẻ, điều này là không thể và điều tốt nhất có thể đạt được là một đỉnh ít hơn (vì chu vi luôn luôn là chẵn).


Đầu ra

Xuất hình dạng dưới dạng một chuỗi các ký tự được phân tách dòng mới ( N hàng gồm các ký tự M chính xác ). Ở đây tôi đang sử dụng không gian cho các hình vuông bên ngoài đa giác và '#' cho các hình vuông bên trong đa giác, nhưng bạn có thể sử dụng bất kỳ hai ký tự riêng biệt trực quan nào, miễn là ý nghĩa của chúng phù hợp với tất cả các đầu vào.

Bạn có thể bao gồm tối đa một dòng mới hàng đầu và tối đa một dòng mới.

Nếu bạn muốn, thay vào đó, bạn có thể xuất M hàng có N ký tự chính xác và bạn có thể chọn đầu ra M by N cho một số đầu vào và đầu ra N by M cho các đầu vào khác.


Ví dụ

Không hợp lệ do một lỗ:

###
# #
###

Không hợp lệ do giao nhau (chạm theo đường chéo - một đỉnh có 4 cạnh vuông trên chu vi) và, ngẫu nhiên, một lỗ:

##
# #
###

Không hợp lệ do bị ngắt kết nối:

#
# #
  #

Đa giác hợp lệ của chu vi tối đa:

# #
# #
###

Tín dụng

Ban đầu tôi đã đánh giá thấp giá trị của chu vi tối đa có thể được tính toán nhanh như thế nào và sẽ chỉ yêu cầu giá trị đó làm đầu ra. Cảm ơn những người hữu ích tuyệt vời trong trò chuyện vì đã giải thích cách tính chu vi tối đa cho N và M tùy ý và giúp biến điều này thành một thách thức sẽ kéo dài hơn một câu trả lời ...

Cụ thể nhờ:

Sparr , Zgarb , frageum , jimmy23013 .


Tôi có thể đặt tên cho câu hỏi này bằng cách sử dụng polyominos hoặc đa giác (vì cả hai đều áp dụng). Có ai có một sở thích? Bạn có thể biểu thị bằng bình luận về những điều sau:
trichoplax

5
Polyomino chu vi cao nhất
trichoplax

1
Chu vi đa giác kết nối cao nhất
trichoplax

N hàng gồm các ký tự M chính xác: chúng ta có thể trao đổi hai giá trị đầu vào nếu chúng ta thấy thuận tiện cho các đầu vào nhất định không?
Cấp sông St

3
@steveverrill Tôi đã chỉnh sửa phần Đầu ra. Điều đó có phù hợp với yêu cầu của bạn?
trichoplax

Câu trả lời:


4

CJam, 47 byte

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

Dùng thử trực tuyến

Giải trình:

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.

Có hai trường hợp chính cho kết quả. Nếu ít nhất một trong các kích thước là số lẻ, thì mẫu đó là "cào" đơn giản. Ví dụ: cho đầu vào 7 6:

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

Nếu cả hai kích thước là chẵn, có một cột thêm trong đó mỗi ô vuông thứ hai là "bật". Ví dụ: cho đầu vào 8 6:

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

Bây giờ, để chỉ ra rằng các mẫu này đạt đến mức tối đa theo lý thuyết của chu vi như được đưa ra trong mô tả vấn đề, chúng ta cần xác nhận rằng mẫu đầu tiên có chu vi (M + 1) * (N + 1)và mẫu thứ hai có cùng giá trị trừ 1.

Đối với mẫu đầu tiên, chúng ta có chu vi, với Mkích thước lẻ:

  1. M cho cạnh trên.
  2. 2 ở phía bên của hàng trên cùng.
  3. (M - 1) / 2 cho các khoảng trống giữa các răng.
  4. (M + 1) / 2răng với chu vi 2 * (N - 1) + 1mỗi.

Điều này thêm vào:

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)

Đối với trường hợp thứ hai có cả hai MNchẵn, chu vi cộng lại từ:

  1. M cho cạnh trên.
  2. 2 ở phía bên của hàng trên cùng.
  3. M / 2 cho # mở ở hàng trên cùng.
  4. M / 2răng với chu vi 2 * (N - 1) + 1mỗi cho răng đồng bằng.
  5. Răng ngoài cùng bên phải có thêm một 2 * (N / 2 - 1)mảnh chu vi cho răng cưa.

Cộng tất cả lại với nhau:

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

Tôi nghĩ rằng tôi có thể lưu một vài byte bằng cách đặt phần răng cưa bên trái. Nên yêu cầu một số ít xáo trộn ngăn xếp. Nhưng đã đến giờ đi ngủ ...
Reto Koradi

5

Ruby, Rev 1, 66

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

Được sử dụng nâng mlên công suất 0 o 1 để quyết định xem 1 hoặc m #'sẽ được in.

Được sử dụng >để kiểm tra hàng cuối cùng thay vì ==.

Không thể thoát khỏi không gian sau khi đặt, cũng không có dấu ngoặc nào!

Ruby, Rev 0, 69

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

Đây là một chức năng lambda ẩn danh. Sử dụng nó như thế này:

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)

Cuối cùng, sau khi hỏi liệu M và N có thể thay thế được không, tôi không cần nó.


Đầu ra điển hình cho N lẻ. Nếu chúng ta tự xóa chúng #ở phía bên tay phải, rõ ràng chúng ta sẽ có (N + 1) (M + 1). Bao gồm chúng để tham gia hình dạng sẽ loại bỏ 2 hình vuông có chu vi ngang và thêm 2 hình vuông có chu vi dọc, do đó không có thay đổi.

Ở đây chúng tôi dựa vào biểu thức "#"*(i%2==0?m:1)để đưa ra các hàng #ký hiệu M và một #ký hiệu xen kẽ , và chứng minh đúng cho các ký tự M.

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

Đầu ra điển hình cho N chẵn. 5 6rõ ràng có cùng chu vi với 6 5, hoặc tăng M + 1 = 6 so với việc 5 5thêm chu vi theo chiều dọc do sự đóng băng của hàng dưới cùng. 6 6có cùng 6 5mức tăng cộng với (M + 1) -1 = 6 theo chu vi dọc. Vì vậy, chúng là phù hợp với công thức.

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

Thật tiện dụng khi Ruby rjustcho phép bạn chỉ định phần đệm để sử dụng cho các ô trống. Thông thường phần đệm được đặt thành " "nhưng đối với hàng cuối cùng chúng ta chuyển sang "# "(lưu ý rằng phần đệm sẽ chỉ cần thiết ở hàng cuối cùng nếu N chẵn. Trong đó N là số lẻ, hàng cuối cùng sẽ hoàn thành và sẽ không có lý do nào, vì vậy bạn sẽ không nhìn thấy các vết nứt.)

Kiểm tra nó ở đây.


@ Vioz- Cảm ơn các ideone! Tôi đã thử nghiệm chương trình xuống các giá trị thấp của N và M để xem liệu có trường hợp cạnh nào không, nhưng tôi không buồn kiểm tra xem nó có hoạt động với các giá trị cao không. Rõ ràng cả crenname và crenelation đều đúng, vì vậy tôi sẽ bỏ nó. Sẽ quay lại sau để xem liệu tôi có thể xóa một số dấu ngoặc và khoảng trắng không.
Cấp sông St

Không có vấn đề cho các liên kết? Tôi cho rằng nó sẽ hữu ích cho những người khác vì tôi đã sử dụng nó để kiểm tra: P Liên quan đến chỉnh sửa chính tả, tôi đã thay đổi nó thành kết quả đầu tiên tôi có thể tìm thấy, bởi vì tôi chưa bao giờ thấy từ này thực sự được sử dụng. Tôi không biết nhiều về Ruby (không có gì, Infact), nhưng bạn có thể thay đổi i%2==0để i%2<1tiết kiệm một byte (Tôi đã thực hiện thay đổi này để liên kết ideone).
Kade

Bạn có thực sự cần phần #đệm cho hàng cuối cùng không? Ví dụ, trong hình cuối cùng, không phải chu vi giống nhau mà không có #góc dưới cùng bên phải?
Reto Koradi

@RetoKoradi nó thực sự sẽ có cùng chu vi - có vẻ như mã bao gồm phần bổ sung #đơn giản vì nó đã là cách mọi dòng kết thúc, vì vậy nó ít byte hơn là đặt một khoảng trắng ở đó. (Tôi không biết ruby ​​mặc dù ...).
trichoplax

1
@trichoplax trực giác của bạn là chính xác. Việc đệm "# "không phải là " #"vì cái sau sẽ cho 2 liền kề #cho M lẻ mà chắc chắn là không muốn. 2 liền kề #cho M thậm chí không có hại, vì vậy tôi đã đi với nó. Tôi chưa thử ljust, có thể làm điều đó rõ ràng hơn với điều đó, nhưng sẽ không rõ ràng khi tôi in chính xác M ký tự trên mỗi hàng.
Cấp sông St

5

C, 109 97 byte và bằng chứng chính xác

Tôi đã viết ra giải pháp của mình nhưng @steveverrill đã đánh bại tôi. Tôi nghĩ rằng tôi sẽ chia sẻ tất cả giống nhau, vì tôi đã bao gồm một bằng chứng chính xác cho chiến lược được sử dụng.

Mã giảm:

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

Trước khi giảm:

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

Chiến lược và bằng chứng:

Giả sử tính chính xác của phương trình perimiter tối đa (M + 1) (N + 1) - ((M + 1) (N + 1)) mod 2 , sau đây giải thích chiến lược tối ưu được sử dụng và chứng minh tính đúng đắn của nó bằng cảm ứng:

Đối với M lẻ, chúng ta vẽ một hình dạng giống bàn tay với các ngón tay M / 2 + 1, ví dụ:

3x2
# # 
###

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

Bây giờ chúng tôi chứng minh chiến lược này là tối ưu cho tất cả M lẻ bằng cảm ứng:

Trường hợp cơ sở: M = N = 1
Ô duy nhất được điền. Giải pháp đúng vì (1 + 1) * (1 + 1) = 2 * 2 = 4 và một hình vuông có 4 cạnh.

Cảm ứng về chiều rộng:
Giả sử rằng chiến lược hình bàn tay hoạt động cho (N, M-2) trong đó M là số lẻ, nghĩa là, giá trị của nó là tối ưu và là (N + 1) (M - 2 + 1) + ((M -1) (N + 1)) mod 2 . Bây giờ chúng tôi cho thấy rằng nó sẽ hoạt động cho (N, M) .

Quá trình thêm một ngón tay sẽ loại bỏ một cạnh khỏi đa giác và thêm 3 + 2N . Ví dụ:

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

Kết hợp điều này với giả thuyết của chúng tôi rằng chu vi trước đó là tối ưu, chu vi mới là:

(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

Vì chúng ta đang làm việc với số học modulo 2,

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

Do đó, việc chứng minh rằng việc tăng chiều rộng bằng cách thêm ngón tay sẽ dẫn đến chu vi tối ưu.

Cảm ứng về chiều cao:
Giả sử chiến lược hình dạng bàn tay hoạt động cho (N-1, M) , trong đó M là số lẻ, nghĩa là chu vi của nó là tối ưu và là mod N (M + 1) + ((M + 1) N) 2 . Bây giờ chúng tôi cho thấy rằng nó sẽ hoạt động cho (N, M) .

Tăng chiều cao của bàn tay chỉ đơn giản là kéo dài các ngón tay, nằm ở đầu tiên và mọi chỉ số x khác. Đối với mỗi lần tăng chiều cao, mỗi ngón tay thêm hai vào chu vi và có (M + 1) / 2 ngón tay, do đó, việc tăng N dẫn đến tăng 2 (M + 1) / 2 = M + 1 trong chu vi.

Kết hợp điều này với giả thuyết, chúng ta có chu vi mới là:

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

Số học mô-đun cho phép chúng tôi đơn giản hóa thuật ngữ cuối cùng, để chúng tôi có được:

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

Chứng minh rằng giải pháp là tối ưu cho tất cả N> 0 và M> 0 lẻ.

Đối với ngay cả M, chúng tôi điền vào bảng giống như với M lẻ, nhưng chúng tôi thêm các dấu ngoặc vào phân đoạn cuối, ví dụ:

4x3
# ##
# # 
####

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

Bây giờ chúng tôi chứng minh rằng chiến lược này là tối ưu.

Cảm ứng cho M chẵn:
Giả sử rằng giải pháp là đúng cho (N, M-1), với M-1 lẻ (như đã được chứng minh trong trường hợp cuối cùng), có chu vi tối ưu là (N + 1) M - ( M (N + 1)) mod 2 . Bây giờ chúng tôi cho thấy rằng nó sẽ hoạt động cho (N, M).

Giống như tăng các ngón tay, mỗi dấu ngoặc kép thêm hai vào chu vi của đa giác. Tổng số lượng vỏ là (N + N mod 2) / 2 , với tổng chu vi N + N mod 2 được thêm vào.

Kết hợp điều này với giả thuyết, chúng ta có chu vi mới là:

(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

Chúng tôi có điều đó

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

Bởi vì nếu N là số lẻ, thì giá trị này giảm xuống 0 = 0 và nếu N là số chẵn thì nó giảm xuống còn

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

Do đó, chiến lược là tối ưu cho tất cả M, N> 0 .


2
Đó là rất nhiều toán học! Bạn không thể tính chu vi của hình bạn đang tạo và cho thấy nó phù hợp với giá trị tối đa được cung cấp? Bạn biết bạn có bao nhiêu "ngón tay", mỗi ngón tay dài bao nhiêu, v.v ... Vì vậy, việc tính chu vi sẽ rất dễ dàng.
Reto Koradi

Thật. Ở một số khía cạnh, tôi cảm thấy đường dẫn cảm ứng trực quan hơn, vì nó là phụ gia, nhưng vâng, nó dẫn đến một lời giải thích dài hơn.
André Harder

Bạn có thể muốn biết chu vi bằng với số điểm nguyên mà nó đi qua.
jimmy23013
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.