Java – 使用贝尔曼-赫尔德-卡普算法进行基于规则的排序

huangapple go评论89阅读模式
英文:

Java - Rule-based sorting using bellman-held-karp algorithm

问题

我在CS SE上提出了以下问题,但对于如何在Java中实现答案毫无头绪(更不用说理解其实际含义):

我试图在花园里种植一排作物。某些植物对其他植物有益,对另一些植物有害,我试图找到最佳的植物顺序:最多相邻的友好植物,且没有相邻的敌对植物,如在这个表格中定义的(我已列出每种植物的一个示例):

编号 植物名称      友好植物      敌对植物
1   西瓜         7,4,3        8,6
2   番茄         9,8,6,5,1    7
3   向日葵       7,6,11  
4   西葫芦       9,7,3   
5   茄子         9,6,2        7,10
6   黄瓜         9,7,3        8,1
7   玉米         8,6,4,3,1    5,2
8   哈密瓜       7,4,3        6,1
9   甜椒         6,5,11,10,2 
10  甜菜         2            5
11  大黄         9,3 

我该如何找出植物的排列顺序?

“Jakube”回答道:
> 你可以通过简单地迭代所有n!种不同的排列,检查每个排列是否允许,并且评估每个排列的好坏来解决这类问题。这个方法的复杂度为O(n⋅n!)。
>
> 更快(但仍具有指数复杂度)的方法是对贝尔曼-赫尔德-卡普算法进行变种。对于每对(V,v),其中V是所有蔬菜的子集,v∈V,计算是否可以以v为最后一个植物来排列蔬菜V,以及最佳值是多少。你可以为这个函数定义一个递归公式,并应用动态规划,就像在BHK算法中一样。这应该在O(n<sup>2</sup>⋅2n)的时间内运行。"

我最初提出了一个关于每种植物只有一个的情况,但我现在意识到我需要一个可以处理更多重复情况的答案。我不确定他给出的答案是否适用于我拥有多个相同种类植物的情况。

英文:

I asked the following question on CS SE, and have no idea as to how to implement the answer in java (let alone make out what it is actually saying):

I am trying to plant a row in a garden. Certain plants are good for some plants and bad for others, and I am trying to find the best order of plants: most adjacent friends and no adjacent foes, as defined in this table (I have one of each):

Num Vegetable     Friends      Foes
1   Watermelon    7,4,3        8,6
2   Tomatoes      9,8,6,5,1    7
3   Sunflowers    7,6,11  
4   Zucchini      9,7,3   
5   Eggplant      9,6,2        7,10
6   Cucumbers     9,7,3        8,1
7   Corn          8,6,4,3,1    5,2
8   Cantaloup     7,4,3        6,1
9   Bell peppers  6,5,11,10,2 
10  Swiss chard   2            5
11  Rhubarb       9,3 

How do I find the arrangement?

"Jakube" answered:
> You can solve such a problem by simply iterating over all n! different
> permutations, and checking each if any of the arrangements is allowed
> and how good it is. This has complexity O(n⋅n!).
>
> Much faster (but still exponential complexity) will be a variation to
> the Bellman–Held–Karp algorithm. Compute for each pair (V,v) with V
> being a subset of all vegetables and and v∈V, if it is possible to
> arrange the vegetables V in a way such that v is the last one and what
> it's best value is. You can define a recursive formula for this
> function, and apply dynamic programming, like in the BHK algorithm.
> That should run in O(n<sup>2</sup>⋅2n)."

I originally asked the question for a case where I had one of each, but now realize that I need an answer which can take more an occasional duplicate. I am not sure if the answer he gave is applicable to a case where I have more than one of a given plant.

答案1

得分: 1

import collections

Plant = collections.namedtuple("Plant", ("id", "name", "friends", "foes"))

def extend(first_plant, result):
    objective, other_plants = result
    return (
        (first_plant.id in other_plants[0].friends)
        + (other_plants[0].id in first_plant.friends)
        + objective,
        [first_plant] + other_plants,
    )

def best_order_recursive(first_plant, other_plants, cache):
    if not other_plants:
        return 0, [first_plant]
    cache_key = (first_plant.id, frozenset(plant.id for plant in other_plants))
    if cache is None:
        cache = {}
    else:
        cache_value = cache.get(cache_key)
        if cache_value is not None:
            return cache_value
    value = max(
        (
            extend(
                first_plant,
                best_order_recursive(
                    next_plant, other_plants[:i] + other_plants[i + 1 :], cache
                ),
            )
            for (i, next_plant) in enumerate(other_plants)
            if first_plant.id not in next_plant.foes
            and next_plant.id not in first_plant.foes
        ),
        default=(float("-inf"), [first_plant]),
    )
    cache[cache_key] = value
    return value

def best_order(plants):
    cache = {}
    return max(
        best_order_recursive(first_plant, plants[:i] + plants[i + 1 :], cache)
        for (i, first_plant) in enumerate(plants)
    )

def main():
    objective, plants = best_order(
        [
            Plant(1, "Watermelon", {7, 4, 3}, {8, 6}),
            Plant(2, "Tomatoes", {9, 8, 6, 5, 1}, {7}),
            Plant(3, "Sunflowers", {7, 6, 11}, set()),
            Plant(4, "Zucchini", {9, 7, 3}, set()),
            Plant(5, "Eggplant", {9, 6, 2}, {7, 10}),
            Plant(6, "Cucumbers", {9, 7, 3}, {8, 1}),
            Plant(7, "Corn", {8, 6, 4, 3, 1}, {5, 2}),
            Plant(8, "Cantaloupe", {7, 4, 3}, {6, 1}),
            Plant(9, "Bell peppers", {6, 5, 11, 10, 2}, set()),
            Plant(10, "Swiss chard", {2}, {5}),
            Plant(11, "Rhubarb", {9, 3}, set()),
        ]
    )
    print(objective)
    print(*(plant.name for plant in plants), sep=", ")

if __name__ == "__main__":
    main()
英文:

I know you tagged this Java, but here's some Python implementing that dynamic program.

import collections
Plant = collections.namedtuple(&quot;Plant&quot;, (&quot;id&quot;, &quot;name&quot;, &quot;friends&quot;, &quot;foes&quot;))
def extend(first_plant, result):
objective, other_plants = result
return (
(first_plant.id in other_plants[0].friends)
+ (other_plants[0].id in first_plant.friends)
+ objective,
[first_plant] + other_plants,
)
def best_order_recursive(first_plant, other_plants, cache):
if not other_plants:
return 0, [first_plant]
cache_key = (first_plant.id, frozenset(plant.id for plant in other_plants))
if cache is None:
cache = {}
else:
cache_value = cache.get(cache_key)
if cache_value is not None:
return cache_value
value = max(
(
extend(
first_plant,
best_order_recursive(
next_plant, other_plants[:i] + other_plants[i + 1 :], cache
),
)
for (i, next_plant) in enumerate(other_plants)
if first_plant.id not in next_plant.foes
and next_plant.id not in first_plant.foes
),
default=(float(&quot;-inf&quot;), [first_plant]),
)
cache[cache_key] = value
return value
def best_order(plants):
cache = {}
return max(
best_order_recursive(first_plant, plants[:i] + plants[i + 1 :], cache)
for (i, first_plant) in enumerate(plants)
)
def main():
objective, plants = best_order(
[
Plant(1, &quot;Watermelon&quot;, {7, 4, 3}, {8, 6}),
Plant(2, &quot;Tomatoes&quot;, {9, 8, 6, 5, 1}, {7}),
Plant(3, &quot;Sunflowers&quot;, {7, 6, 11}, set()),
Plant(4, &quot;Zucchini&quot;, {9, 7, 3}, set()),
Plant(5, &quot;Eggplant&quot;, {9, 6, 2}, {7, 10}),
Plant(6, &quot;Cucumbers&quot;, {9, 7, 3}, {8, 1}),
Plant(7, &quot;Corn&quot;, {8, 6, 4, 3, 1}, {5, 2}),
Plant(8, &quot;Cantaloupe&quot;, {7, 4, 3}, {6, 1}),
Plant(9, &quot;Bell peppers&quot;, {6, 5, 11, 10, 2}, set()),
Plant(10, &quot;Swiss chard&quot;, {2}, {5}),
Plant(11, &quot;Rhubarb&quot;, {9, 3}, set()),
]
)
print(objective)
print(*(plant.name for plant in plants), sep=&quot;, &quot;)
if __name__ == &quot;__main__&quot;:
main()

huangapple
  • 本文由 发表于 2020年8月20日 19:46:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/63504391.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定