从浮点数的向量
std::vector<float> v { 0.32, 0.0004, 12.78, -9.2, 1.1 };
我试图找出可以在每个浮点数前面放置的“+”和“ - ”系列,以获得尽可能接近值GOAL
的结果。请注意,不能省略任何数字(必须使用所有值)。
float GOAL = 4.9;
对于这个例子,我认为最好的解决方案是
+ 0.32 - 0.0004 + 12.78 + (-9.2) + 1.1 = 4.9996
让true
表示“+”而false
表示“ - ”,最佳解决方案可以表示为
std::vector<bool> solution { true, false, true, true, true }
可以迭代所有可能的组合。如果n
的大小为v
,则有2 ^ n种可能的组合。当n
变大时,过程变得非常慢(2 ^1000≈10^ 301)。
我怎样才能编写一个搜索算法,在多项式时间内输出的效果不是最好但是下降的解决方案?
仅供参考,我对搜索算法只有基本的了解。我理解启发式算法,贪心算法,爬山,搜索树,极小极大游戏树等概念。
答案 0 :(得分:2)
我只是给出了一个基本算法来实现这一目标。
1)计算可用浮点数的长度。 (我假设长度是固定的)。
2)有一个数组(长度为1)。全零。 3)然后尝试在浮点数之间执行操作。(零指负值)。 4)如果它与GOAL不匹配,则通过假设数组为二进制数来递增数字。 5)重复步骤3&amp; 4直到它与GOAL匹配。 6)即使最后如果不匹配,也不可能。
Ex:浮动矢量大小为5.然后所有可能的操作都是
步骤2:0000 - &gt; (第1 - 第2 - 第3 - 第4 - 第5)
步骤3:0001 - &gt; (第1 - 第2 - 第3 - 第4和第5)(增量二进制数)
步骤4 :((1st-2nd-3rd-4th + 5th)!= GOAL) - &gt;增加并调用Step3。所以,0010
它将通过所有可能性进行计算。
答案 1 :(得分:1)
不确定这是否符合您的多项式时间要求,但遗传算法往往在这种优化方面做得很好。
另外,作为一个实现细节,由于您要添加大量浮点数,您可能需要查看Kahan summation以最小化浮点错误。
答案 2 :(得分:1)
我没有看到优雅的解决方案,但......以下是基于递归函数(模板函数,因此您可以将其与double
和long double
一起使用而无需更改)
#include <cmath>
#include <vector>
#include <iostream>
template <typename F>
F getSol (std::vector<F> const vals, F const & goal,
std::vector<bool> & sol, std::size_t const & used,
F const & sum)
{
F ret;
if ( used == vals.size() )
{
ret = sum;
}
else
{
std::vector<bool> sol1 { sol };
std::vector<bool> sol2 { sol };
sol1.push_back(true);
sol2.push_back(false);
F ret1 { getSol(vals, goal, sol1, used+1U, sum+vals[used]) };
F ret2 { getSol(vals, goal, sol2, used+1U, sum-vals[used]) };
if ( std::fabs(ret1 - goal) < std::fabs(ret2 - goal) )
{
ret = ret1;
sol = std::move(sol1);
}
else
{
ret = ret2;
sol = std::move(sol2);
}
}
return ret;
}
int main()
{
std::vector<float> v { 0.32, 0.0004, 12.78, -9.2, 1.1 };
std::vector<bool> solution;
float goal { 4.9f };
float res { getSol(v, goal, solution, 0U, 0.0f) };
std::cout << "the result is " << res << std::endl;
std::cout << "the solutions is ";
for ( auto const & b : solution )
std::cout << b << ", ";
std::cout << std::endl;
}
答案 3 :(得分:1)
我们可以考虑贪婪算法,它在 O(n)时间内提供下降解决方案。
算法 :
让数组和目标为:
vector<float> v { 0.32, 0.0004, 12.78, -9.2, 1.1 };
float GOAL = 4.9;
现在开始迭代第一个索引中的向量,并贪婪地选择符号,即
If "+" :
diff = |Goal- ValueTillNow| = |4.9-0.32| = 4.58
If "-" :
diff = |Goal- ValueTillNow| = |4.9-(-0.32)| = 5.22
既然我们希望 ValueTillNow
与目标接近,我们会贪婪地选择&#34; +&#34;第一次漂浮。
现在类似于数组中的rest index。更新 ValueTillNow
。计算两个选项的差异,即"+"
和"-"
,然后选择距离目标更接近GOAL的选项。
时间复杂度:O(n)
答案 4 :(得分:1)
对我来说看起来像integer linear programming问题。
我会把它分成两个线性整数程序,第一个用于超越GOAL,第二个用于进入GOAL。因此,为您提供以下两个程序,其中b_i = 0
代表-
,而b_i = 1
代表{ans}中的+
。
结束,从而最大限度地减少:
min Sum(v_i - 2 * b_i * v_i)
s.t. Sum(v_i - 2 * b_i * v_i) > GOAL
b_i >= 0
b_i <= 1
b_i is an int
max Sum(v_i - 2 * b_i * v_i)
s.t. Sum(v_i - 2 * b_i * v_i) < GOAL
b_i >= 0
b_i <= 1
b_i is an int
然后应用通常的算法来解决两个LP并看到更好的解决方案。 如果让算法运行到最后,那么问题就是NP难。但是有些算法可以在有限的步骤之后提供合理的解决方案。