预赛
首先,我们定义一个line类,其中包含2个点的坐标:
import itertools
import random
class line(object) :
"""
A line has 2 ends.
"""
def __init__(self, tup0, tup1 ) :
self.tup0 = tup0
self.tup1 = tup1
def __repr__( self ) :
return "line[{0}, {1}]".format( self.tup0, self.tup1 )
def StartPoint(self) :
return self.tup0
def EndPoint(self):
return self.tup1
def reverseLine(self) :
return line( self.tup1, self.tup0 )
解决方案
我只是枚举所有可能的形状(有效或无效),直到找到 2 个闭合形状:
- 我列举了行列表中所有可能的 2 路分区
- 给定分区的每个集群都是一个可能的形状。为了实际验证这一点,我列举了集群中所有可能的线顺序排列(以及每条线的终点的所有可能顺序)
- 一旦我找到了一个可以验证我们标准的分区(即每个集群都是一个封闭的形状),我打印解决方案并停止
这里是帮手:
def is_closed( lines ) :
"""
Return True if lines represents a closed shape (i.e., order matters)
"""
are0ToNConnected = all( l.tup1 == lines[i+1].tup0 for i,l in enumerate( lines[:-1] ) )
areFirstAndLastConnected = ( lines[-1].tup1 == lines[0].tup0 )
return are0ToNConnected and areFirstAndLastConnected
def is_any_closed( lines ) :
"""
Return True if at least one re-ordering of lines represents a closed shape (i.e., order doesnt matter)
"""
return any( is_closed(newLines)
for permutedLines in itertools.permutations( lines )
for newLines in itertools.product( * [ ( l, l.reverseLine() ) for l in permutedLines ] ) )
def k_way_partition( A, k ) :
"""
Generator for all k-way partitions of A
"""
if k == 1 :
yield [ A ]
elif len(A) == k :
yield [ [ a ] for a in A ]
else :
for partition in k_way_partition( A[1:], k ) : # add new element to one of the current clusters
for i, cluster in enumerate( partition ) :
yield partition[:i] + [ cluster + [ A[0] ] ] + partition[i+1:]
for partition in k_way_partition( A[1:], k-1 ) : # add new element to a new cluster
yield [ [ A[0] ] ] + partition
这是主要功能:
def find_shapes( lines, k ) :
"""
Looks for a partition of lines into k shapes, and print the solution if there is one.
"""
for partition in k_way_partition( lines, k ) :
if all( is_any_closed(cluster) for cluster in partition ) : # we found a solution
for j, cj in enumerate( partition ) :
print "shape {}: {}".format(j, cj )
break
示例
让我们生成随机数据并尝试解决方案:
# square
lines = [ line( (0,0), (0,1) ) ]
lines.append( line( (0,1), (1,1) ) )
lines.append( line( (1,1), (1,0) ) )
lines.append( line( (1,0), (0,0) ) )
# triangle
lines.append( line( (2,2), (2,3) ) )
lines.append( line( (2,3), (3,2) ) )
lines.append( line( (3,2), (2,2) ) )
lines
random.shuffle( lines ) # randomize the order of lines
for i, l in enumerate( lines ) :
if random.random() < 0.5 :
lines[i] = l.reverseLine() # randomize order of coordinates
lines
输出[8]:
[line[(0, 1), (1, 1)],
line[(1, 1), (1, 0)],
line[(2, 2), (2, 3)],
line[(0, 0), (1, 0)],
line[(3, 2), (2, 2)],
line[(3, 2), (2, 3)],
line[(0, 0), (0, 1)]]
现在让我们在随机数据上运行我们的解决方案:
find_shapes( lines, 2 )
shape 0: [line[(3, 2), (2, 3)], line[(3, 2), (2, 2)], line[(2, 2), (2, 3)]]
shape 1: [line[(0, 0), (0, 1)], line[(0, 0), (1, 0)], line[(1, 1), (1, 0)], line[(0, 1), (1, 1)]]
有效!