最小重量三角测量永远

时间:2013-03-04 00:59:28

标签: polygon minimum triangulation decomposition

所以我一直在用Python编写一个程序,找到凸多边形的最小权重三角剖分。这意味着它找到了权重(所有三角形周长的总和),以及和弦列表(通过多边形的线条将其分解成三角形,而不是边界)。

我的印象是我正在使用动态编程算法,但是当我尝试使用更复杂的多边形时,它需要花费很长时间(我不知道需要多长时间,因为我还没有完成它)。

它可以很好地使用10边多边形,但是我正在尝试25,这就是让它失速的原因。我的老师给了我多边形,所以我认为这个多边形应该可以工作。

由于这个算法应该是O(n^3),所以25边多边形的计算时间应该大约需要15.625倍,但是看到10边看起来很快就会更长。

我在那里做了某种我没有意识到的操作吗?我无法看到我正在做的任何事情,除了最后一部分我可以通过将列表转换为集合来摆脱重复项,但是在我的程序中,我在转换之前在转换之后放置了跟踪,并且它不是甚至达到了这一点。

这是我的代码,如果你们需要更多信息,请问。那里的东西让它花费的时间比O(n^3)长,我需要找到它,所以我可以修剪它。

#!/usr/bin/python
import math

def cost(v):
    ab = math.sqrt(((v[0][0] - v[1][0])**2) + ((v[0][1] - v[1][1])**2))
    bc = math.sqrt(((v[1][0] - v[2][0])**2) + ((v[1][1] - v[2][1])**2))
    ac = math.sqrt(((v[0][0] - v[2][0])**2) + ((v[0][1] - v[2][1])**2))
    return ab + bc + ac

def triang_to_chord(t, n):
    if t[1] == t[0] + 1:
        # a and b
        if t[2] == t[1] + 1:
            # single
            # b and c
            return ((t[0], t[2]), )
        elif t[2] == n-1 and t[0] == 0:
            # single
            # c and a
            return ((t[1], t[2]), )
        else:
            # double
            return ((t[0], t[2]), (t[1], t[2]))
    elif t[2] == t[1] + 1:
        # b and c
        if t[0] == 0 and t[2] == n-1:
            #single
            # c and a
            return ((t[0], t[1]), )
        else:
            #double
            return ((t[0], t[1]), (t[0], t[2]))
    elif t[0] == 0 and t[2] == n-1:
        # c and a
        # double
        return ((t[0], t[1]), (t[1], t[2]))
    else:
        # triple
        return ((t[0], t[1]), (t[1], t[2]), (t[0], t[2]))


file_name = raw_input("Enter the polygon file name: ").rstrip()
file_obj = open(file_name)
vertices_raw = file_obj.read().split()
file_obj.close()

vertices = []

for i in range(len(vertices_raw)):
    if i % 2 == 0:
        vertices.append((float(vertices_raw[i]), float(vertices_raw[i+1])))

n = len(vertices)

def decomp(i, j):
    if j <= i: return (0, [])
    elif j == i+1: return (0, [])

    cheap_chord = [float("infinity"), []]
    old_cost = cheap_chord[0]
    smallest_k = None

    for k in range(i+1, j):
        old_cost = cheap_chord[0]
        itok = decomp(i, k)
        ktoj = decomp(k, j)
        cheap_chord[0] = min(cheap_chord[0], cost((vertices[i], vertices[j], vertices[k])) + itok[0] + ktoj[0])
        if cheap_chord[0] < old_cost:
            smallest_k = k
            cheap_chord[1] = itok[1] + ktoj[1]

    temp_chords = triang_to_chord(sorted((i, j, smallest_k)), n)
    for c in temp_chords:
        cheap_chord[1].append(c)
    return cheap_chord

results = decomp(0, len(vertices) - 1)
chords = set(results[1])
print "Minimum sum of triangle perimeters = ", results[0]
print len(chords), "chords are:"
for c in chords:
    print "   ", c[0], "  ", c[1]

我将添加我正在使用的多边形,第一个立即解决,而第二个已经运行了大约10分钟。

第一个:

202.1177      93.5606
177.3577     159.5286
138.2164     194.8717
73.9028     189.3758
17.8465     165.4303
2.4919      92.5714
21.9581      45.3453
72.9884       3.1700
133.3893      -0.3667
184.0190      38.2951

第二个:

397.2494     204.0564
399.0927     245.7974
375.8121     295.3134
340.3170     338.5171
313.5651     369.6730
260.6411     384.6494
208.5188     398.7632
163.0483     394.1319
119.2140     387.0723
76.2607     352.6056
39.8635     319.8147
8.0842     273.5640
-1.4554     226.3238
8.6748     173.7644
20.8444     124.1080
34.3564      87.0327
72.7005      46.8978
117.8008      12.5129
162.9027       5.9481
210.7204       2.7835
266.0091      10.9997
309.2761      27.5857
351.2311      61.9199
377.3673     108.9847
390.0396     148.6748

1 个答案:

答案 0 :(得分:0)

看起来这里有一个低效率的重复问题。

...
def decomp(i, j):
...
for k in range(i+1, j):
    ...
    itok = decomp(i, k)
    ktoj = decomp(k, j)
    ...
...

你遇到了与naive recursive implementation of the Fibonacci Numbers相同的问题,但是这种算法的工作方式,在运行时可能会更糟糕。假设这是你算法的唯一问题,那么你只需要使用记忆来确保只为每个唯一输入计算一次分解。

发现此问题的方法是将i,j和k的值打印为三元组(i,j,k)。为了获得O(N ^ 3)的运行时间,您不应该两次看到相同的精确三元组。然而,三联(22,24,23)至少出现两次(在25中),并且是第一次这样的重复。这表明该算法多次计算相同的事情,这是低效的,并且正好比O(N ^ 3)提高了性能。我会留下算法算法的实际性能对你来说是一个练习。假设算法没有其他问题,算法最终应该停止。