具有修改的树的动态编程

时间:2017-07-13 22:17:29

标签: algorithm tree dynamic-programming depth-first-search

最近我在树上读到了一个问题但我发现很难解决这个问题。这是问题:

n个城市(2到10 ^ 5)(n-1)双向道路的国家,可以在任何一对之间旅行城市。我们有 1魔术卡车可以在城市之间旅行但是需要 1个单位时间(如果它已加载) 0单位时间(如果没有加载)< / strong>在相邻城市之间旅行,最多可以保留1个产品单元

现在,您可以在任何城市拥有正好2个产品单元的客户,并且不能等待超过2个单位的时间。

现在的问题是,我们必须尽量减少存储总数,并给出限制:

  1. 一个城市不能有多个存储空间。
  2. 存储只能存储1个单位的产品。
  3. 在国家/地区分配存储空间,以便您可以按时填写至少第一个订单。鉴于订单可以放在任何城市。

    时间限制:1秒

    我尝试了什么:

    1. 我认为最糟糕的做法是蛮力。尝试在每个城市放置存储(2 ^ n种可能性)并检查是否可以在邻近城市的帮助下完成每个城市秩序。但是时间复杂度将是(n * 2 ^ n)。所以根本不会起作用。

    2. 我想的第二种方法是以某种方式在树上使用DP。而且我也不确定这是否是最优的。从上面的问题我可以确保叶子肯定有1个存储。我在想DP,从root开始检查孩子是否可以帮助完成它的顺序并相应地为该城市分配存储,有叶子的基础案例。但问题在于,孩子们也可以从父母那里完成订单,所以它正在制作循环循环。所以,它也没有帮助我。

    3. 我最后的方法是考虑在答案本身上应用二进制搜索。由于答案可以介于(1,n)之间,因此可以在nLog(n)顺序中找到答案。但问题是,我无法想到在具有特定存储空间的城市中分配存储的最佳方式。

    4. 所以,就是这样..我努力但却无法解决这个问题。任何帮助,将不胜感激。 :)

      注意:我不知道为什么他们这样复杂的问题陈述如此复杂。他们可以用更简单的方式轻松解释问题。结果我再也找不到网络上的这个问题了。我想这是代码系统的某个地方。

1 个答案:

答案 0 :(得分:4)

关于图表需要注意的重要事项是,有n个城市和n-1条道路,所有城市都可以到达;这意味着:

  • 没有循环路径。
  • 至少有2个单独连接的城市(终点)。

每个城市都有两种可能性;要么:

  • 该市有一个储存设施,另外一个储存设施最多可以在2个城市之外。
  • 该市没有储存设施,并且至少与两个拥有储存设施的城市相连。

这也意味着一个单独连接的城市(道路的终点)总是有一个存储设施,一串双重连接的城市应该(最佳地)交替地拥有一个存储设施,这将给我们决定储存设施放置位置的起点。

City storage animation

blue:当前节点;绿色:存储;橙色:没有储存; +:需要另一个带存储的邻居; ?:已访问但尚未解决

这为我们提供了以下算法:

  • 首先找到一个终点:从任何城市开始向任何方向移动 直到你来到一个单一连接的城市。
  • 在单独连接的城市中放置一个存储设施,然后返回 以前的城市,标志着你来自这座城市的道路 访问。
  • 如果这个城市只有另一条未经检查的道路,请继续前行 没有访问过的道路,留下了相邻城市的痕迹 储存设施。
  • 如果你来到一个有多条未经检查的道路的城市,请等待 决定是否放置存储设施并采取任何一个 未经检查的道路;以后当你回到这个城市的时候 只有一条未经访问的道路,你会知道是否已经有了 访问邻近城市需要这个城市有一个存储 设施。
  • 这样做直到你最终进入一个没有未经检查的道路的城市;这个 意味着你已经完成了整个图表。

这基本上是“沿着所有道路行进并且再次回溯”算法,因此被访问节点的数量是2×N并且复杂度是线性的或O(N)。

值得注意的是,访问城市的顺序不会改变结果,即存储设施的数量,但可能会改变其部分位置。考虑4个城市的这两个解决方案:

S - / - S - S   (solved left to right)  
S - S - / - S   (solved right to left)  

靠近实际代码,让我们看看一旦确定了终点后该怎么做。该图由例如节点组成。这个:

NODE "city" C1
- neighbours: [C2, C4, C7]
- has_storage: undefined          <- at first; will be set to true/false
- needs_more_storage: true/false  <- we'll add this property as we go
- visited: true/false             <- we'll add this property as we go

我们从一个终点开始,然后对于每个节点,我们将:

  • 将节点标记为已访问。
  • 查看相邻节点:如果只找到一个未定义的节点,请确定当前节点的has_storage:如果所有邻居'i> has_storage 都为false或任何邻居'i> needs_more_storage 为true,将当前节点的 has_storage 设置为true;如果没有,将 has_storage 设置为false,如果只有一个相邻的城市有存储,则将 needs_more_storage 设置为true;然后移动到一个未定义的邻居。
  • 如果未定义多个相邻节点,请移至未访问过的任何节点。
  • 如果没有任何相邻节点未定义,则表示您已到达最后一个节点;这始终是一个终点,所以将其 has_storage 设置为true;算法现已完成。