我有一个生成如下变体的函数:111,112,...,133,211,212,...,233,311,...,333。生成的序列的长度总是匹配字典的长度;有4个符号,它是1111到4444。
这是在用于图形着色的强力算法中完成的。我们试图找到具有尽可能少的不同颜色的正确序列,即如果12343和12321都是解决方案,我们更喜欢后者。
现在我去检查每个序列是否正确,然后将最佳结果保存在过程中。这不是一个好的代码。
所以教授让我写一个能按特定顺序产生变化的函数。这些序列应按其不同数量的顺序排序,如:111,222,333; 112,113,121,......,323; 123,213。在这种情况下,如果我们发现121,这是正确的,我们就停止,因为我们已经知道这是最好的解决方案。
我们的想法是尽可能多地跳过序列检查,以便代码运行得更快。请帮助:)
现在我使用这段代码:
初始化功能
std::vector<int> res; //contains the "alphabet"
res.reserve(V);
for (int i = V - 1; i >= 0; i--) {
res.push_back(i);
}
std::vector<int> index(res.size());
std::vector<int> bestresult(V); //here goes the best answer if it's found
for (int i = V - 1; i >= 0; i--) {
bestresult.push_back(i);
}
int bestcolors = V;
permutate(res, index, 0, bestresult, bestcolors);
result = bestresult;
重排列:
void Graph::permutate(const std::vector<int>& s, std::vector<int>& index, std::size_t depth, std::vector<int>& bestres, int &lowestAmountOfColors)
{
if (depth == s.size()) {
//doing all needed checks and saving bestresult here;
return;
}
for (std::size_t i = 0; i < s.size(); ++i) {
index[depth] = i;
permutate(s, index, depth + 1, bestres, lowestAmountOfColors);
}
}
如何更改这些功能?
答案 0 :(得分:1)
挑战在于找到所有颜色的排列,以便您可以测试它们是否是有效的图形着色。不幸的是,它是指数级的。因此,我们需要首先检查最小的解决方案来搜索排列,我们需要大幅度地修剪解决方案空间。
要首先找到最小的解决方案,我们必须限制可用的颜色数量,并在增加颜色数量之前消耗这些排列。很简单。我们只需要一个考虑N个顶点的n种颜色的函数。顶点的数量保持不变,但我们认为n = 1,然后n = 2,等等。
在函数中,我们知道我们需要1,2和... n的各种组合,并且具有足够的重复以获得总共N个不同的值。所以我制作了一个计数器。该向量有n个条目,值总和为N.
例如,如果我们正在考虑具有7个顶点的图的三种颜色解,那么将使用一个可能的计数数组{4,3,1}来生成候选{1,1,1,1,2 ,2,2,3}。颜色1出现4次。颜色2出现3次。颜色3出现1次。
关于此计数数组的一个很酷的事情是,只要它被排序为最大到最小,那么它的组合不能复制我们考虑过的任何其他组合,因为颜色是可互换的。 (好吧,不完全准确,当颜色具有相同的数量时会有一些重复,但是我们从被查看中消除了许多排列,这是重点)。
将计数数组减少到实际候选解决方案后,您可以使用组合找到所有排序,而不是排列。这将产生更少的候选人。谷歌next_combination找到一些好的代码显示如何做到这一点。
当我们生成计数数组时,我将所有值初始化为1,然后将所有剩余计数添加到第一种颜色。我搜索满足计数数组的所有组合。然后我通过将计数向右移动来获得下一个候选者,使其保持排序。
总而言之,find_minimum_graph_coloring有一个调用solve_for_n的for循环。该函数为n的值生成所有可能的计数数组,并调用另一个函数。该函数检查该count-array的所有组合。
第一个for循环首先检查较少数量的颜色,因此我们可以在找到解决方案后立即返回。 count-array表示法消除了许多等效的颜色,因此如果我们考虑{1,1,2},那么我们将永远不会尝试{2,2,1}