我有std::vector<Problem> problems
,我需要生成相应的std::vector<Solution> solutions
。
我有一个算法可以为给定的Solution
生成一个候选Problem
,但需要注意的是我尝试生成的 order 会影响整个集合是否可以得到解决。
// This function exists already. Solution::ok() tells us whether it worked.
Solution solve (
const Problem &,
const std::vector<Solution> & solutions_so_far);
Solution
的存在不仅取决于已经解决的问题,而且解决方案的性质也会发生变化,因此我无法缓存任何结果。
我需要一种算法来探索problems
的所有排列,根据需要进行回溯,并在找到完整的解决方案后立即返回。
我们要求solutions[i]
对应problems[i]
,否则输出的特定顺序无关紧要。请注意,上面的solutions_so_far
表示problems
可能已经被洗牌。
这是我需要实现的界面
// Returns a corresponding list, or an empty list if no complete solution found
std::vector<Solution> solve (
std::vector<Problem>::iterator begin,
std::vector<Problem>::iterator end)
{
// ???
}
现在我被卡住了。我该怎么做?
另外,我可以就地进行吗?即使用std :: move重新排序problems
是可以的,但理想情况下我不想在堆上分配任何东西。我想这个函数可以在它递归之前改变输入,但是我不能使这个模糊的想法具体化,或者说服自己我完全覆盖搜索空间而不重复任何工作。
答案 0 :(得分:1)
您可以在索引引用的问题集上执行算法,因此不会创建副本,只需索引排列:
std::vector<Solution> solve(std::vector<Problem>::iterator begin,
std::vector<Problem>::iterator end)
{
// Create a solution
std::vector<Solution> ret(std::distance(begin, end));
// Define the search space
std::vector<int> indices(std::distance(begin, end)); // problem space
std::iota(indices.begin(), indices.end(), 0); // fill with the indices
do
{ // The mapping "solution-problem" can be done through the permutation state
int i(0);
for (auto it(indices.begin()), ite(indices.end()); it != ite; ++it)
{
ret[i] = solve(*(begin+(*it)), ret); // solve should acept ret range
if (ret[i++].ok())
{
if (it + 1 == ite) return ret; // all solved !
}
else break; // try another permutation
}
} while (std::next_permutation(indices.begin(), indices.end()));
return std::vector<Solution>(); // empty list
}
索引向量是必需的,因为std :: next_permutation需要“&lt;”运算符定义为(在这种情况下)问题类(或comp函数)并且没有提到这样的函数(在MSVC中你得到“错误C2678:二进制'&lt;':没有找到一个带左手操作数的运算符类型'问题'(或没有可接受的转换)“)
答案 1 :(得分:0)
本书combinatorial generation有一个函数,它将排列的词典列表映射到第66页的整数。例如:
F4(0) = [1,2,3,4]
F4(1) = [1,2,4,3]
所有你需要的只是一个迭代器,它接受一个排列(表示为索引数组)并按顺序迭代你的两个列表。这将要求您在堆上分配一个大小为N的数组(其中N是输入向量的长度)。
我会警告你,虽然你过了8个左右的项目,你根本无法遍历所有的排列(只有太多)。
如果您绝对无法分配任何内存,那么您可以放弃重新排序输入列表,但这会增加代码的复杂性。
答案 2 :(得分:0)
我想我有,但我不确定这是否正确。也许有人可以一眼就看出来?
首先,单个案件解决方案。
typedef std :: vector <Problem> P;
typedef std :: vector <Solution> S;
bool solve (
P :: iterator problem,
S :: iterator so_far_start,
S :: iterator so_far_end,
Solution * output)
{
if (/* can find s consistent with [so_far_start...so_far_end)*/)
{
*output = s;
return true;
}
else
return false;
}
将此扩展到有序列表。
bool solve_naive (
P :: iterator begin,
P :: iterator end,
S :: iterator out_begin,
S :: iterator out_end)
{
auto in = begin;
auto out = end;
while (in < end)
{
if (! solve (in, out_begin, out, &*out))
return false;
++in;
++out;
}
return true;
}
现在聪明一点。
// reordering problems [at...end) as needed,
// write out corresponding solutions [out_at...out_end)
// consistent with [out_begin...out_at)
bool solve_permutations (
P :: iterator at,
P :: iterator end,
S :: iterator out_begin,
S :: iterator out_at,
S :: iterator out_end,
unsigned * limit)
{
if (end == at)
return true;
if (0 == -- *limit)
return false;
if (solve_naive (at, end, out_at, out_end))
return true;
// try each other input in first position, let
// recursion solve for some ordering of the remainder
for (auto in = at + 1; in < end; ++in)
{
std :: swap (*in, *at);
// this one must be solvable in first position
if (! route (at, out_begin, out_at, &*out_at))
continue;
// all the rest must be solvable in any position
if (solve_permutations (
at + 1,
end,
out_begin,
out_at + 1,
out_end,
limit))
{
return true;
}
}
return false;
}
将所有这些结合在一起。
S solve_hopefully (P :: iterator begin, P :: iterator end)
{
S solutions (end - begin, {});
if (end - begin < WIDTH_LIMIT)
{
unsigned limit = DEPTH_LIMIT;
// Will help if this high-level function
// is called repeatedly.
std :: random_shuffle (begin, end);
return solve_permutations (
begin,
end,
solutions .begin (),
solutions .begin (),
solutions .end (),
& limit)
? solutions : S ();
}
else for (unsigned i = 0; i < SHUFFLE_LIMIT; ++i)
{
std :: random_shuffle (begin, end);
if (solve_naive (begin, end, solutions .begin (), solutions .end ())
return solutions;
}
return {};
}
这对你们好吗?