给定一个树高度列表,找到可能减少它们的次数最少

时间:2017-11-19 07:26:45

标签: python algorithm data-structures

我试图解决的问题是,想象一下每列中树的数量列表,例如: [10,20,10,0],此列表中的每个元素都是该列中存在的树的数量,表示在第一列中有十棵树,在第二列中有20棵树,依此类推。列数是固定的,通过剪切列,其数量将变为零。如果可能的话,你可以完全减少一行或一列,但是你只能在连续的行或列中减少,这意味着如果你有[4,0,4]则不能减少行以减少所有树木。 对于[4,0,4],只需要两次尝试,减少第一列和第三列。我会给你另一个例子,想象你有一个[4,3,4,3,4]列表,你可以减少三行并使其成为[1,0,1,0,1]但是你必须删除三列,总共需要6个步骤,但您也可以删除所有需要5个步骤的列,任何其他解决方案的结果都将大于5个步骤。

编辑:此图片将澄清问题: 首先,切割具有4个元素的列,然后切割第一行,然后切割现在有2个元素的列,然后切割最后一行或列。正如我之前所说,你不能削减具有不连续性的行。 (行中存在的所有元素应相邻,以便能够向下切割行)(在此图中,行#3具有不连续性) enter image description here

我正试图解决这个问题两天,我无处可去。我的最新代码在这里,在非正方形中进入几乎无限循环,例如[例如3个元素的列表,其中元素最多为200]树列表。

    def cut_tree_row(tree):
    res = []
    discontinoue_flag = 0 # A flag to findout if cutting down the row is possible or not
    non_zero_flag_once = 0 # if the program encounters a non_zero element for the first time this would change to 1
    non_zero_flag_twice = 0# if the program encounters a non_zero element for the second time while the discontinue flag is 1, it would change to 1
    for i in xrange(len(tree)):
        if tree[i] > 0:
            non_zero_flag_once = 1
            if non_zero_flag_once == 1 and discontinoue_flag == 1:
                non_zero_flag_twice = 1
            else:
                res.append(tree[i]-1)
        else:
            if discontinoue_flag == 0 and non_zero_flag_once == 1:
                discontinoue_flag = 1
            if discontinoue_flag == 1 and non_zero_flag_twice == 1:
                return [], 10000000
            res.append(0)
    if discontinoue_flag == 1 and non_zero_flag_twice == 1:
        return [], 10000000

    return res , 1

def cut_tree_column(tree):

    res = []
    max_index = 0
    m = max(tree)
    flag = 1
    if len(tree) == 0:
        return tree , 0
    for i in xrange(len(tree)):
        if tree[i] == m and flag == 1:
            flag = 0
            res.append(0)
            continue
        res.append(tree[i])
    return res , 1


def find_min_attempts(tree, total_sum = 0):
    if len(tree) == 0:
        return total_sum
    s = sum(tree)
    if s == 0:
        return total_sum
    res1 , num1 = cut_tree_column(tree)
    res2 , num2 = cut_tree_row(tree)
    return  min(find_min_attempts(res1, total_sum + num1),find_min_attempts(res2, total_sum + num2))



def main():
    tree = [187, 264, 298, 924, 319] #This input gives me an infinite loop
    print find_min_attempts(tree)

main()

1 个答案:

答案 0 :(得分:1)

此递归解决方案计算切割最大列之后的步数,以及最大行。它返回两者中的最小值。

如果存在零,则它将每个不连续部分解决为子问题。

def get_max_col(t):
    """ Get index of tallest column """
    return max(enumerate(t),key=lambda x: x[1])[0]

def remove_max_col(t):
    """ Remove tallest column """
    idx = get_max_col(t)
    new_t = t[:]
    new_t[idx] = 0
    return new_t

def remove_bottom_row(t):
    """ Remove bottom row """
    return [x - 1 for x in t]

def splitz(iterable, val):
    """ Split a list using val as the delimiter value """
    result = []
    group = []
    for e in iterable:
        if e == val:
            if group: # ignore empty groups 
                result.append(group)
                group = [] # start new 
        else:
            group.append(e)
    if group: # last group
        result.append(group)

    return result

def min_cuts(t):
    # All zeroes, finished
    if set(t) == set([0]):
        return 0

    # Single column
    if len(t) == 1:
        return 1

    # All ones, single row
    if set(t) == set([1]):
        return 1

    # If discontinued, add cost of subproblems
    if 0 in t:
        sub_ts = splitz(t, 0)
        return sum(map(min_cuts, sub_ts))
    # try removing the largest column and largest row(bottom)
    # Pick the cheapest one
    else:
        t1 = remove_max_col(t)
        x = 1 + min_cuts(t1)

        t2 = remove_bottom_row(t)
        y = 1 + min_cuts(t2)

        return min(x, y)

print(min_cuts([4,3,4,3,4]))
print(min_cuts([187, 264, 298, 924, 319]))