Có phải là cây tuyến tính? (Phiên bản đầu tiên)


11

Lý lịch

Một cây không ghi nhãn có thể trông như thế này:

   o
 / | \
o  o  o
|    / \
o   o   o

Để tuyến tính hóa cây này, trước tiên chúng ta gắn nhãn cho mỗi nút obằng số nút con của nó:

   3
 / | \
1  0  2
|    / \
0   0   0

và sau đó viết các số trong một danh sách theo cách dễ hiểu, nghĩa là từng dòng và từ trái sang phải:

[3, 1, 0, 2, 0, 0, 0]

Đây là một đại diện độc đáo và rõ ràng của cây ở trên, có nghĩa là không có hai cây thuần khác nhau sẽ có cùng tuyến tính hóa và chúng ta có thể xây dựng lại cây ban đầu từ danh sách.

Mặc dù mỗi cây tương ứng với một danh sách số nguyên nhất định, nhưng không phải mỗi danh sách số nguyên đại diện cho một cây được tuyến tính hóa hợp lệ: Ví dụ: [2, 0, 0, 0]không đại diện cho một cây hợp lệ, nếu chúng ta cố gắng phi tuyến tính hóa, chúng ta sẽ kết thúc với cây này

[2,0,0,0] -> 2 [0,0,0] -> 2 [0,0] -> 2 [0]
            / \          / \        / \
                        0          0   0

nhưng vẫn còn một 0danh sách trong danh sách và không có nơi nào để đặt nó. Tương tự như vậy [2, 0]cũng không phải là một tuyến tính cây hợp lệ, vì cây phi tuyến tính có một điểm con trống:

  2
 / \
0

Bài tập

Đưa ra một danh sách số nguyên, quyết định xem đó có phải là một tuyến tính hợp lệ của cây bằng cách sử dụng càng ít byte càng tốt hay không. Bạn có thể viết một chương trình đầy đủ hoặc một chức năng.

Dữ liệu vào: Danh sách các số nguyên không âm.

Đầu ra: Một giá trị trung thực nếu danh sách là tuyến tính hóa của cây, nếu không thì giá trị giả.

Tủ thử

Sự thật
[0]
[2, 0, 0]
[1, 1, 1, 1, 1, 0]
[3, 1, 0, 2, 0, 0, 0]
[2, 0, 2, 2, 0, 0, 2, 0, 0]
[3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0]
[1, 5, 3, 0, 2, 1, 4, 0, 1, 0, 0, 2, 1, 0, 0, 1, 1, 0, 0, 0, 0, 2, 1, 0, 0, 1, 0]
Giả
[0, 1]
[2, 0]
[2, 0, 0, 0]
[1, 0, 1]
[3, 2, 1, 0]
[2, 0, 0, 2, 0, 0]
[4, 1, 0, 3, 0, 0, 0, 0]
[4, 2, 0, 3, 1, 0, 0, 0, 0, 0]

Câu trả lời:


4

Haskell, 44 byte

f[n:k]=iterate f[k]!!n
f _=[]
g x=f[x]==[[]]

Xác định hàm glấy danh sách và trả về boolean. Xem nó vượt qua tất cả các trường hợp thử nghiệm .

Giải trình

Điều này phụ thuộc vào thực tế là tuyến tính hóa chiều sâu đầu tiên và chiều rộng đầu tiên tạo ra các mảng giống nhau. Xem câu trả lời của Martin để biết chi tiết; về cơ bản cả hai đều đưa ra điều kiện số học giống nhau trên mảng.

Hàm fđược đưa ra danh sách đầu vào được bọc trong danh sách đơn. Nó bật một số nra khỏi danh sách, sau đó gọi chính nó nlần trong danh sách còn lại để xử lý các phần tử con của nút bật (độ sâu trước). Popping kết quả danh sách trống [], mà tôi sử dụng như là một trạng thái lỗi. Hàm gkiểm tra kết quả cuối cùng là [[]], trạng thái không sai duy nhất không có nút chưa được xử lý. Nếu Haskell được gõ yếu, tôi chỉ có thể sử dụng 0hoặc một cái gì đó làm trạng thái lỗi và sẽ không phải bọc đầu vào vào một danh sách khác.


3

Toán học, 38 byte

Last@#<0<=Min@Most@#&@Accumulate[#-1]&

Ý tưởng cơ bản là chúng tôi theo dõi một số nút để điền vào. Mỗi phần tử trong danh sách sử dụng tối đa một nút và thêm bao nhiêu là có con. Vì vậy, mỗi phần tử ithay đổi tổng số đếm theo i-1. Số này bị tắt bởi một, bởi vì nên bắt đầu từ 1(gốc), không phải 0.

Để cây có hiệu lực, chúng tôi không bao giờ có thể đi xuống dưới 0danh sách, bởi vì chúng tôi sẽ không có nơi nào để đặt nút hiện tại và b) cần kết thúc -1ở cuối, nếu không chúng tôi còn lại các nút không sử dụng.

Chúng tôi có được tổng số các nút còn lại đang chạy với Accumulate[#-1](tính tổng các tiền tố của danh sách đầu vào trừ đi một). Và sau đó chúng tôi kiểm tra phần tử cuối cùng và chỉ phần tử cuối cùng -1có:

Last@#<0<=Min@Most@#

Lưu ý rằng việc kiểm tra phần tử cuối cùng là âm là đủ, vì chúng ta không bao giờ có thể giảm nhiều hơn 1, vì vậy nếu các giá trị cuối cùng là -2hoặc thấp hơn thì tối thiểu các phần tử khác sẽ không âm.


2

Võng mạc , 29 byte

\d+
$*
^(?<-1>(1)*,)*$(?(1)!)

Hãy thử trực tuyến! (Dòng đầu tiên cho phép bộ kiểm tra được phân tách bằng nguồn cấp.)

Giải trình

Ý tưởng cơ bản giống như câu trả lời Mathicala của tôi : chúng tôi theo dõi tổng số nút còn lại đang chạy, đảm bảo nó không bao giờ xuống dưới 0 mà kết thúc bằng 0. Tuy nhiên, cách thức này được thực hiện với regex rất khác nhau.

\d+
$*

Điều này chỉ đơn giản là chuyển đổi đầu vào thành đơn nguyên, biến mỗi số nguyên nthành n1s.

^(?<-1>(1)*,)*$(?(1)!)

Đây là nơi phép màu thực sự xảy ra. Đó là một regex khá ngắn chỉ phù hợp với các cây hợp lệ, nhưng cơ chế của nó khá tinh tế.

Tôi đang sử dụng các nhóm cân bằng để theo dõi số lượng nút, đây là một cách để làm việc với các ngăn xếp bên trong regex.

Trước hết, tất nhiên một ngăn xếp như vậy không bao giờ có độ sâu âm, vì vậy chúng ta thực sự không thể kết thúc bằng một đại diện -1ở cuối, như chúng ta làm trong giải pháp Mathicala. Tuy nhiên, chúng ta có thể lưu ý rằng phần tử cuối cùng của các đầu vào được không trên một chồng hợp lệ (nếu không chúng ta không thể kết thúc với -1). Nó chỉ ra rằng nó thực sự tiết kiệm byte để kiểm tra cả hai chúng ta kết thúc bằng 0 và với các nút còn lại bằng không.

Vì vậy, đây là một sự cố của regex:

^        e# Anchor the match to the beginning of the string.
(?<-1>   e# Each repetition of this group will match one number. 
         e# We can ignore the <-1> for now.
  (1)*   e#   Match each unary digit of the current number, pushing
         e#   a capture onto stack 1. This increments our total of
         e#   remaining nodes by 1 for each child.
  ,      e#   Match a comma. Note that this requires that there is at
         e#   least one more number in the list.
)*       e# At the end of the repetition the <-1> pops one capture from
         e# the stack. This is the node that the current number itself
         e# takes up.
$        e# Match the end of the string. This requires the input to end
         e# in a zero, because the last thing we matched was a comma.
(?(1)!)  e# Make sure that stack 1 is empty, so that we don't have any
         e# unused nodes.

1

CJam (20 byte)

{X0@{+\(_0>{\}*}/|!}

Bộ kiểm tra trực tuyến . Đây là một khối ẩn danh lấy một mảng trên ngăn xếp và để lại 0 hoặc 1 trên ngăn xếp.

Mổ xẻ

Trong mã giả này là:

p = 1
q = 0
foreach (i in input):
  q += i
  if (--p <= 0):      # in practice, if (--p == 0):
      p, q = q, p
return (p | q) == 0   # i.e. p == 0 && q == 0

qtích lũy tổng số nhãn của các nút ở cấp độ hiện tại trong cây; pđếm ngược các nút còn lại ở mức hiện tại.


{X0@{+\(_{\}&}/|!}Tôi nghĩ?
Martin Ender

Ngoài ra, có vẻ như bạn sẽ có thể lưu một byte bằng cách sử dụng một chương trình đầy đủ để tránh @.
Martin Ender

1

Mê cung , 17 byte

(
+?
;-)
,_"
@@,!

Hãy thử trực tuyến!

Đầu ra trung thực là -1và đầu ra giả là trống rỗng. Xác định sự thật và giả dối trong Labyrinth là một chút khó khăn, bởi vì các chi nhánh của Labyrinth chủ yếu là tạm thời. Tuy nhiên, cách duy nhất để xây dựng một điều kiện với hai nhánh đáng tin cậy, bạn chỉ có thể làm điều này:

>"F
 T

Trong trường hợp này, tôi sẽ xem xét di chuyển thẳng về phía trước giả (vì hướng di chuyển không bị ảnh hưởng) và biến thành sự thật. Chúng tương ứng với 0 và khác không. Lý do tôi sử dụng đầu ra trống để biểu thị số 0 là vì, nếu bạn chuyển đầu ra trở lại vào một chương trình Labyrinth khác, toán tử đầu vào ?thực sự sẽ đẩy số 0 nếu đầu vào trống, vì vậy tôi coi chuỗi trống là hợp lệ đại diện của số không.

Giải trình

Thuật toán vẫn giống như trong các câu trả lời Mathicala và Retina của tôi, nhưng do luồng điều khiển của Labyrinth, lần này nó hoạt động hơi khác một chút:

  • Chúng tôi không làm việc với tổng số lượt truy cập tại đây. Thay vào đó, chúng tôi a) làm việc với bộ đếm âm và b) khởi tạo nó thành -11ban đầu, để chúng tôi muốn bộ đếm âm trong toàn bộ danh sách và đạt 0 trên đầu vào cuối cùng. Điều này thực sự đơn giản hóa dòng điều khiển ở đây.
  • Thay vì xây dựng danh sách đầy đủ và kiểm tra xem nó có chứa giá trị sai hay không, có ba điều kiện chấm dứt có thể xảy ra:

    1. Chúng tôi đạt EOF trước khi đạt tổng số không. Trong trường hợp đó, có các nút không được sử dụng còn lại và chúng tôi không in gì cả.
    2. Chúng tôi đạt đến 0 chúng tôi đang ở EOF. Trong trường hợp này, chúng tôi đã có một cây hợp lệ.
    3. Chúng tôi đạt đến 0 và chưa có tại EOF. Trong trường hợp này, chúng tôi đã hết các nút trước khi bao gồm tất cả các yếu tố và chúng tôi không in gì cả.

Đối với mã thực tế, chúng tôi bắt đầu ở góc trên cùng bên trái. Biến (số 0 ẩn trên đỉnh của ngăn xếp thành a -1, sẽ là tổng số đang chạy. Sau đó chúng tôi nhập vào vòng lặp chính rất chặt chẽ của chương trình , +?-)"_,;+:

+   Add the top two values. This does nothing on the first iteration,
    but gets rid of a helper-zero on subsequent iterations.
?   Read and push integer.
-   Subtract it from running total.
)   Increment.
"   No-op. There is a branch at this point. If the running total is zero,
    we move straight ahead onto the , (see below). Otherwise, the loop continues.
_   Push a zero. This is necessary to prevent the IP from turning south.
,   Read a character. This will either be the next separator (some positive
    number) or EOF (-1). If it's EOF, the IP turns south and the program
    terminates. Otherwise, the loop continues.
;   Discard the separator.

Điều đó chỉ để lại các trường hợp chúng tôi đã giảm tổng số chạy xuống 0 tại một số điểm. IP di chuyển sang phía dưới bên phải ,và đọc một ký tự khác để kiểm tra xem chúng tôi đã đạt EOF chưa. Nếu không, giá trị sẽ dương và IP quay về hướng tây @và chương trình chấm dứt. Nếu chúng tôi đã đạt EOF, IP sẽ quay về hướng đông và in -1bằng !. IP sau đó sẽ đi sâu về phía dưới bên trái @thông qua một con đường hơi kỳ lạ để chấm dứt chương trình.


0

Python, 82 byte

lambda l:len(l)==sum(l)+1 and not any(list(l[x]>=len(l)-x for x in range(len(l))))

Cần nhiều trường hợp kiểm tra.


Bạn không cần phải sử dụng listít nhất nếu đây là Python 2 và bằng cách sắp xếp lại và đảo ngược điều kiện thứ hai, bạn có thể lấy nó thành 70 byte:lambda l:all(l[x]<len(l)-x for x in range(len(l)))and len(l)==sum(l)+1
Kade

^ Liên quan đến điều này, bạn có thể thay đổi cơ thể của allx<len(l)-y for y,x in enumerate(l)để tiết kiệm thêm 2 byte để làm cho nó 68.
Kade

Bây giờ tôi không chơi gôn nữa vì tôi không nghĩ đó là một giải pháp chính xác. Cảm ơn vì những lời khuyên.
Sparr

0

Bình thường, 13 byte

qxsM._tMQ_1tl

Chúng tôi bắt đầu bằng cách tính độ đầy hiện tại của cây tại tất cả các điểm trong biểu diễn đầu vào. Phần ý tưởng đó phần lớn được mượn từ Martin Ender, vì vậy cảm ơn ông.sM._tMQ

Khi chúng tôi có danh sách này, chúng tôi kiểm tra xem chỉ mục đầu tiên có chứa -1( x..._1) có phải là độ dài của đầu vào trừ đi một ( q...tl(Q)) không.

Đừng tin nó hoạt động? Hãy tự thử!

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.