【问题标题】:Given a list of tree heights find the least attempts possible to cut them down给定一个树高列表,找到尽可能少的尝试来减少它们
【发布时间】:2017-11-19 07:26:45
【问题描述】:

我要解决的问题是,假设您有一个每列中树数的列表,例如[10,20,10,0],此列表中的每个元素都是该列中存在的树的数量,这意味着在第一列中您有 10 棵树,在第二列中您有 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()

【问题讨论】:

  • 您的问题陈述没有多大意义。您有一个树高列表,但随后您谈论行和列,并且不再使用“高度”一词。 “行”和“列”与树木和高度有什么关系?在您的示例中,“砍伐一列”似乎与砍伐一棵整棵树是一回事,但“砍伐一行”似乎意味着将所有树木的高度减少一个单位。你能澄清一下吗?高度为 0 是什么意思? [10, 20, 10, 0] 与 [10, 20, 10] 有何不同?
  • @PaulCornelius 我添加了一张图片并试图更好地说明问题。切割一列意味着将其无效,该列仍然存在,但其值变为零。高度为零意味着该列中树的高度为零,我知道这听起来很傻,但问题就是这样。减少一排意味着如果可以减少一排,则将所有高度减少一个单位。在我添加的图像中,您不能削减第三行(从底部),因为第三列有 2 个元素并且行元素不相邻。 /
  • /在我的解决方案中,我只是将第一行剪掉。
  • 这是一个非常有趣的问题。我会要求社区的有经验的用户在投反对票之前花点时间
  • @FarhoodET,我认为暴力解决方案并不难。但它看起来像是来自在线法官,如果是这样的话,预期的时间复杂度是多少? O(N^2) 可以吗?

标签: python algorithm data-structures


【解决方案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]))

【讨论】:

  • 这似乎可行,但在您的第二个示例中,它的效率非常低。您总是有一个可能的解决方案,即分别削减每一列。因此,这里的优化是在达到 len(t) 深度时终止递归。
猜你喜欢
  • 2021-07-12
  • 2010-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多