值排列
问题:有 2 个并行的正值数组 A
和 B
,大小为 n
。
如何找到以下目标函数的最小值:
F(A, B) = Ak + Bk * F(A', B')
其中 A'
、B'
表示数组 A
和 B
及其 k
:第一个元素被删除。
我正在考虑动态规划方法,但没有成功。
如何应用于此类问题,我们需要在排列上评估给定函数?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
最佳解决方案是计算
(B_k - 1)/A_k
,并在递归的最外侧位置执行结果较小(包括负数较多)的结果。这是局部最优的,因为您无法交换一对相邻的选择并进行改进,因此也是全局最优的,因为该算法除了
(B_k-1)/A_k
的相等值之外还给出了唯一的解决方案,其中没有什么区别。任何其他不具有此属性的解决方案都不是最佳的。如果我们将
A_1+B_1*(A_2+B_2*F)
与A_2+B_2*(A_1+B_1*F)
进行比较,则前者会更小(或相等)当且仅当注意到
A_k > 0 。
空
F(,)
的值并不重要,因为它出现在最后乘以所有B_k
。The optimal solution is to calculate
(B_k - 1)/A_k
and do those with smaller (including more negative) results on the most outside position of the recursion.This is locally optimal in that you cannot swap a pair of adjacent choices and improve, and therefore globally optimal, since the algorithm gives a unique solution apart from equal values of
(B_k-1)/A_k
, which make no difference. Any other solution which does not have this property is not optimal.If we compare
A_1+B_1*(A_2+B_2*F)
withA_2+B_2*(A_1+B_1*F)
then the former will be smaller (or equal) iffnoting
A_k > 0
.The value of the empty
F(,)
does not matter, as it appears in the end multiplied by all theB_k
.我想出了一个启发式方法。可惜这不是最优的(感谢 yi_H!) =(
起初,我认为从增加
A_i
的值开始。但是,反例仍然存在(A={1000, 900}
和B={0.1, 0.5}
)所以我想出了这个:对于
[1..n]
中 i 的每个值,计算V_i = A_i + B_i*min(A_j) for j!=i
选择 i,使
V_i
是所有中最小的V
值从 A 和 B 中删除A_i
和B_i
。这是前两项,与
A'
和 < code>B' 直到结束(直到两者都为空)。如果您记住 V_i 并更新它们,则该算法为 O(n^2),否则对于简单的实现,该算法为 O(n^3)
编辑:恭喜 yi_H 。寻找反例来说明为什么这不是最佳的!
I've come up with a heuristic. Too bad it is not optimal (thanks yi_H!) =(
At first, I thought that starting with increasing values of
A_i
. However, counterexamples remained (A={1000, 900}
andB={0.1, 0.5}
) So I came up with this :For each value of i in
[1..n]
, computeV_i = A_i + B_i*min(A_j) for j!=i
Choose i such that
V_i
is the smallest among all theV
values. RemoveA_i
andB_i
from A and B. These are the two first terms.Repeat with
A'
andB'
until the end (until both are empty).The algorithm is O(n^2) if you memorize the
V_i
and update them, otherwise it's O(n^3) for a naive implementation.Edit : Congrats for yi_H for finding counter-examples showing why this is non optimal!
不是解决方案,但可能是一种启发。看看
F(A, B) = Ak + Bk * F(A', B')
,很明显F(A', B')
正在发生大于Ak
或Bk
。因此,由于相乘,我们应该选择尽可能小的Bk
,这将为我们提供一个k
值,因此可能是最小的F(A , B)
当我们计算出来时。如果有多个最小的Bk
,我们可以计算它们并选择最小的。然后,我们可以启动一个强力算法,遍历所有可能的结果,但我们已经有一个可能的最小结果,因此,如果当前的试验将给我们带来比我们已有的结果更大的结果,我们可以提前终止。
Not a solution, but a likely heuristic. Looking at
F(A, B) = Ak + Bk * F(A', B')
it seems pretty obvious thatF(A', B')
is going to be larger thatAk
orBk
. Hence, because of the multiplication we should pickBk
to be as small as possible, which will give us a value ofk
and hence a possible smallestF(A, B)
when we calculate it out. If there is more than one smallestBk
we can calculate them all and pick the smallest.We can then start a brute force algorithm ploughing through all the possible results, but we already have a likely smallest, so we can terminate early if our current trial is going to give us a result larger than we already have.
它不是有效的 [ O(2^n * n) ] 但应该可以工作并且比评论中的 O(n! *n) 更好
你可以在没有递归的情况下对其进行编码:
PS:我使用所有元素都是正数,即
a< ;b&& c ac
It's not effectively [ O(2^n * n) ] but should works and better than O(n! *n) as in comments
You can code it without recursion:
PS: I use that all elements are positive i.e
a<b && c<d => ac<bd
我有一个循环,它尝试列表中两个元素的每个组合 (N^2) 并尝试交换它们。如果结果(我用 k=1 进行评估)变得更好,则从头开始。
似乎适用于 N<=10,也可能适用于较大的 N,但我无法真正测试,因为验证器是强力 O(N!) 算法:D 另外,我不知道它有多快对于大 Ns 收敛。
尝试过随机算法,该算法随机选择交换位置并在 X 次不成功的尝试后停止......它很少找到最佳解决方案。
更新:
在Python中运行:
所有测量都包含预排序(第四个Fezvez算法)的运行时间。如果有人认为他的解决方案接近最佳,请告诉我,我会测试它。
更新2:
我的算法在改进后重新开始搜索,这有点愚蠢。我不想重新运行所有测试,这里有一些新数据(仍然无法验证结果,你必须想出一个效果更好的算法。 .:)) 现在有了 Fezvez+swap 的改进:
一些改进统计数据(N=200,均匀分布:A: [1, 1000], B: [0.1,0.9])
I have a loop which tries every combination (N^2) of two element in the list and tries to swap them. If the result (I'm evaluating with k=1) got better, it starts from the beginning.
Seems to be working for N<=10, might be good for larger N as well, but I can't really test because the verifier is the brute force O(N!) algorithm :D Also, I have no idea how fast it converges for large Ns.
Tried randomized algorithm which picks the swap positions randomly and stops after X unsuccessfull tries... it rarely finds the best solution.
Update:
Running in python:
All measurements contain the running time of pre-sort (the 4th one Fezvez's algorithm). If anybody thinks his solution gets close to the optimal please let me know, I'll test it.
Update2:
My algo restared the search after an improvement which was kinda dumb.. I don't want to rerun all test, here is some new data (still can't verify the results, you have to come up with an algorithm which does better..:)) Now with Fezvez+swap improvement:
Some imporevement stats (N=200, uniform dist.: A: [1, 1000], B: [0.1,0.9])
这个解决方案不是最优的,只是实用的。但恐怕这是一个难题。同时,以下内容应该可以为您提供良好的排列。
因为
b_k < 1
,选择使 a_k 增加的排列作为排列是一个很好的起点。您可以根据这个初始猜测尝试模拟退火。作为状态转换的随机换位应该是可以的。
This solution is not optimal, only practical. But I'm afraid this is a hard problem. In the meantime, the following should get you a good permutation.
Since
b_k < 1
, choosing as the permutation the one which makes the a_k increasing is a good starting point.You can try simulated annealing from this initial guess. Random transpositions as state transitions should be OK.