Phân vùng và tái cấu trúc


9

Cho hai hình dạng liền kề của cùng một khu vực, xác định cách tối ưu để chia hình đầu tiên thành số lượng tối thiểu các đoạn liền kề nhau để chúng có thể được sắp xếp lại để tạo thành hình thứ hai. Nói cách khác, tìm số lượng phân đoạn tối thiểu cần thiết có thể tạo thành cả hai hình dạng.

"Tiếp giáp" có nghĩa là mọi ô vuông trong hình có thể được tiếp cận từ bất kỳ ô vuông nào khác bằng cách đi qua các cạnh. Hình dạng và phân khúc được phép có lỗ.

"Sắp xếp lại" có nghĩa là bạn di chuyển các phân khúc xung quanh; bạn có thể dịch, xoay và phản ánh chúng.

Các hình dạng được chứa trên một lưới; nói cách khác, mỗi hình bao gồm một tập hợp các ô vuông đơn vị được nối bởi các góc / cạnh của chúng.

Thông số kỹ thuật đầu vào

Đầu vào sẽ được cung cấp ở một số định dạng hợp lý - danh sách các điểm, mảng chuỗi đại diện cho mỗi lưới, v.v. Bạn cũng có thể lấy kích thước của lưới nếu được yêu cầu. Các lưới sẽ có cùng kích thước và hai hình được đảm bảo có cùng diện tích và diện tích sẽ dương.

Thông số kỹ thuật đầu ra

Đầu ra chỉ nên là một số nguyên dương duy nhất. Lưu ý rằng sẽ luôn có một câu trả lời tích cực vì trong trường hợp xấu nhất, bạn chỉ cần chia các hình dạng thành các Nô vuông đơn vị.

Ví dụ

Các ví dụ được trình bày dưới dạng lưới với .biểu thị một phần trống và #biểu thị một phần của hình dạng.

Trường hợp 1

Đầu vào

.....
.###.
.#.#.
.###.
.....

###..
..#..
..#..
..###
.....

Đầu ra

2

Giải trình

Bạn có thể chia nó thành hai khối hình chữ L gồm 4:

#
###

Trường hợp 2

Đầu vào

#...
##..
.#..
.##.

.##.
####
....
....

Đầu ra

2

Giải trình

Bạn có thể chia các hình dạng như vậy:

A...
AA..
.A.
.BB.

.AA.
BBAA
....
....

Bạn cũng có thể làm:

A...
AA..
.B..
.BB.

.AB.
AABB
....
....

Trường hợp 3

Đầu vào

#....#
######

.####.
.####.

Đầu ra

2

Giải trình

A....B
AAABBB

.ABBB.
.AAAB.

(Trường hợp thử nghiệm này cho thấy sự cần thiết phải xoay / phản chiếu hình dạng để có đầu ra tối ưu)

Trường hợp 4

Đầu vào

.###.
..#..

.##..
.##..

Đầu ra

2

Giải trình

Cho dù bạn chọn các khối như thế nào, việc chọn 2x1 từ hình đầu tiên nhất thiết ngăn không cho hai khối kia được nhóm lại với nhau; do đó, bạn có thể sử dụng một 2x1 và hai 1x1. Tuy nhiên, (cảm ơn @Jonah), bạn có thể chia nó thành hình chữ L 3 khối và một hình vuông duy nhất như vậy:

.AAB.
..A..

.AA..
.BA..


1
Vấn đề thú vị. Và dường như khó khăn. Có bất kỳ thuật toán cho điều này hiệu quả hơn mà vũ phu?
Giô-na

@Jonah Tôi không chắc lắm; Tôi chưa nghĩ đến việc triển khai hiệu quả cho việc này. Âm thanh như một vấn đề DS.
HyperNeutrino

Ngoài ra, có lẽ đáng để thêm nhiều trường hợp thử nghiệm cho một vấn đề phức tạp này.
Giô-na

@Jonah Đề nghị tốt, cảm ơn.
HyperNeutrino

Câu trả lời:


6

Python 3.6 , 799 791 byte

7 byte được lưu bởi Jonathan Frech và motavica

B=frozenset
M=min
X={}
T=lambda s:((x,y)for y,x in s)
N=lambda s:B((x-M(s)[0],y-M(T(s))[0])for x,y in s)
G=lambda s:{(x,y):s&{(x-1,y),(x+1,y),(x,y-1),(x,y+1)}for(x,y)in s}
C=lambda g,s,i=0:i<=len(g)and(len(g)==len(s)or C(g,s.union(*map(g.get,s)),i+1))
F=lambda s:N([(-x,y)for x,y in s])
P=lambda s,i=4:M([N(s),F(s),P(F(T(s)),i-1)],key=list)if i else s
S=lambda s,t=B(),i=0:t|S(s,B().union(u|{p}for u in t for p in s-u if C(G(u|{p}),{p}))if i else B([B([next(iter(s))])]),i+1)if-~i<len(s)else t
def U(s):
 k=P(s)
 if k in X:return
 j=[t for t in S(k)if C(G(k-t),{next(iter(k-t))})];X[k]={P(t):B()for t in j}
 for t in j:X[k][P(t)]|=B([B(P(k-t))]);U(t);U(k-t)
V=lambda s,t:1+M(V(v,w)for u in B(X[s])&B(X[t])for v in X[s][u]for w in X[t][u])if s^t else 1
A=lambda s,t:U(s)or U(t)or V(P(s),P(t))

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

Sử dụng

A(s, t)có hai hình dạng trong đó mỗi hình được đưa ra bởi một danh sách các x, yvị trí lưới.

Một hàm trợ giúp để chuyển đổi biểu diễn đồ họa thành một danh sách các vị trí bên dưới:

def H(g):
 g=g.split("\n")
 return[(x,y)for x in range(len(g[0]))for y in range(len(g))if"#"==g[y][x]]

Thí dụ:

case1_1 = \
""".....
.###.
.#.#.
.###.
....."""

case1_2 = \
"""###..
..#..
..#..
..###
....."""

print(A(H(case1_1), H(case1_2))) # Prints 2

Giải trình

Thuật toán được sử dụng ở đây tốt hơn một chút so với lực lượng vũ phu bằng cách lưu trữ các hình dạng phụ. Đối với một hình dạng nhất định, nó lưu trữ tất cả các cách để chia hình dạng đó thành hai hình dạng liền kề nhau, sau đó tôi bình thường hóa các hình dạng này (thay đổi tọa độ để nó bắt đầu tại điểm gốc, sau đó tìm một phép quay / phản chiếu của nó được sử dụng trong bộ đệm) và lưu trữ chúng trong bộ nhớ cache để tra cứu nhanh chóng sau này. Tất cả các hình dạng phụ sau đó cũng có hình dạng phụ của chúng được lưu vào bộ đệm cho đến khi nó có hình dạng khối đơn.

Các hình dạng phụ này được tạo bằng cách chuyển đổi nó thành danh sách kề đồ thị và sử dụng BFS để tạo tất cả các biểu đồ con. Sau đó, chúng ta có thể lọc các sơ đồ con này thành các sơ đồ mà các đỉnh không bao gồm là một thành phần được kết nối. Xác định xem đồ thị được kết nối có được thực hiện với BFS khác không.

Sau khi bộ đệm hoàn tất, giải pháp được tìm thấy bằng cách so sánh hai hình dạng để tìm các hình dạng phụ mà nó có chung. Khi nó có danh sách các hình dạng phụ này, nó sẽ lấy cặp hình dạng phụ còn lại sau khi loại bỏ hình dạng chung và áp dụng đệ quy cùng một thuật toán một lần nữa để tìm số khối tối thiểu cần thiết để xây dựng lại hình dạng. Điều này sau đó trả về hình dạng phụ với mức tối thiểu của tất cả các giá trị đó và chúng tôi có giải pháp của chúng tôi.

Tôi đã đặt một phiên bản chú thích bên dưới để giải thích từng dòng đang làm gì.

B=frozenset
M=min
# Shapes are stored as a frozenset of tuples where each tuple represents an (x, y) position
# Cache of shape partitions. This is a two-level dictionary where the outer key is a shape, and the inner key is a sub-shape where the value is a list of the shapes left when the sub-shape is removed.
# there may be multiple shapes in the inner-most list if the sub-shape appears multiple times
X={}
# Transpose list of coords (flip around diagonal axis)
T=lambda s:((x,y)for y,x in s)
# Translate shape so its upper-left corner is at the origin
N=lambda s:B((x-M(s)[0],y-M(T(s))[0])for x,y in s)
# Convert shape to graph in adjacency list form
G=lambda s:{(x,y):s&{(x-1,y),(x+1,y),(x,y-1),(x,y+1)}for(x,y)in s}
# Check if graph is connected given a set of nodes, s, known to be connected
C=lambda g,s,i=0:i<=len(g)and(len(g)==len(s)or C(g,s.union(*map(g.get,s)),i+1))
# Flip shape around vertical axis
F=lambda s:N([(-x,y)for x,y in s])
# Converts shape to the minimal reflection or rotation. rotation is equivalent to transpose then flip.
P=lambda s,i=4:M([N(s),F(s),P(F(T(s)),i-1)],key=list)if i else s
# returns all the contiguous sub-shapes of s that contain the first pos, given by next(iter(s))
S=lambda s,t=B(),i=0:t|S(s,B().union(u|{p}for u in t for p in s-u if C(G(u|{p}),{p}))if i else B([B([next(iter(s))])]),i+1)if-~i<len(s)else t
# updates the sub-shape cache, X, recursively for an input shape s 
def U(s):
 k=P(s)
 if k in X:return
 j=[t for t in S(k)if C(G(k-t),{next(iter(k-t))})];X[k]={P(t):B()for t in j}
 for t in j:X[k][P(t)]|=B([B(P(k-t))]);U(t);U(k-t)
# Gets the minimum number of partitions for two shapes
V=lambda s,t:1+M(V(v,w)for u in B(X[s])&B(X[t])for v in X[s][u]for w in X[t][u])if s^t else 1
# The function to run, will update the cache for the two input shapes then return the minimum number of partitions
A=lambda s,t:U(s)or U(t)or V(P(s),P(t))

1
if s==t elsecó thể có thể được đảo ngược, cho phép thay thế !=cho ^.
Jonathan Frech

1
if i<len(s)-1else~> if-~i<len(s)else.
Jonathan Frech

1
def A(s,t):U(s);U(t);return V(P(s),P(t))có thể có thể lambda s,t:U(s)or U(t)or V(P(s),P(t)), tiết kiệm ba byte.
Jonathan Frech

1
s.union(*[g[n]for n in s])~>s.union(*map(g.get,s))
Movatica
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.