英文:
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("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()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论