Algorithm 圆叠加算法
在我制作的游戏中,我需要堆叠一堆不同半径的圆,这样就不会有堆叠重叠。将这些圆堆叠起来,以便重叠的圆与顶部半径最大的圆形成一个堆栈。圆随机放置在连续的二维平面上。可以有半径相等的圆 < >我使用C++。这些圆存储在向量中。关于平面,我只是指圆有(双)x和y坐标。堆栈本质上是使用最上面的一个(应该是最大的)的位置和半径的圆的向量。所谓“无堆叠重叠”,我的意思是堆叠圆后,堆叠不应重叠 我所做的:Algorithm 圆叠加算法,algorithm,graph-algorithm,Algorithm,Graph Algorithm,在我制作的游戏中,我需要堆叠一堆不同半径的圆,这样就不会有堆叠重叠。将这些圆堆叠起来,以便重叠的圆与顶部半径最大的圆形成一个堆栈。圆随机放置在连续的二维平面上。可以有半径相等的圆 < >我使用C++。这些圆存储在向量中。关于平面,我只是指圆有(双)x和y坐标。堆栈本质上是使用最上面的一个(应该是最大的)的位置和半径的圆的向量。所谓“无堆叠重叠”,我的意思是堆叠圆后,堆叠不应重叠 我所做的: 按半径对圆排序 对于第一个圆(最大的一个),将所有重叠的圆添加到其堆栈中,并将其从圆列表中删除 重复此操作
std::vector<std::vector<Symbol>::iterator >symPos; std::vector<int> cons;std::vector<Symbol> selVec; Symbol start; SymbolStack stack;
while(symbols.size()){
std::sort(symbols.begin(),symbols.end(),std::greater<Symbol>());
start = symbols.front();
for(int i = 0;i<symbols.size();i++){
if(symbols[i].getRadius() == start.getRadius()){
selVec.push_back(symbols[i]); cons.push_back(0); symPos.push_back(symbols.begin()+i);
}
}
for(int i = 0;i<selVec.size();i++){
for(int j = i+1;j<selVec.size();j++){
if((selVec[i].getPos()-selVec[j].getPos()).len() < 2*(selVec[i].getRadius()+selVec[j].getRadius())){
cons[i]++;cons[j]++;
}
}
}
int maxCons = 0; int selected;
for(int i = 0;i<cons.size();i++){
if(cons[i] >= maxCons){selected = i;maxCons = cons[i];}
}
start = selVec[selected];
stack.addSymbol(start); symbols.erase(symPos[selected]);
for(auto it = symbols.begin();it!=symbols.end();){
if((it->getPos()-start.getPos()).len() < 1.5*(it->getRadius()+start.getRadius())){
stack.addSymbol(*it);
it = symbols.erase(it);
}else{
it++;
}
}
stacks.push_back(stack);
stack.clear();
selVec.clear();
symPos.clear();
cons.clear();
}
std::vectorsymos;std::向量cons;std::vector selVec;符号启动;符号堆叠;
while(symbols.size()){
std::sort(symbols.begin()、symbols.end()、std::greater());
start=symbols.front();
对于(int i=0;i我将算法分为两部分-代表性检测和堆栈构建,其中堆栈构建基本上将每个圆与代表关联,形成堆栈
最后一部分很简单。迭代每个圆并将其与能量最小的代表关联(可能是最接近的一个)。使用加速数据结构(如网格或kd树)来增强此类查询
第一部分要难得多。事实上,它看起来是NP难的,虽然我不能证明它。但是让我们从一开始
按大小降序排列圆是一个好主意。如果第一个圆(最大半径)没有与相同半径的圆重叠,它显然应该具有代表性。在这种情况下,请从列表中删除(或标记)每个重叠圆。在另一种情况下,您必须决定重叠圆中的哪一个(半径相等的)选择
在您的代码中,您使用一个简单的启发式(重叠圆的数量)来决定选择哪个圆。根据您的数据和用例,这可能是一个有效的选项。一般来说,这可能并不总是导致最佳解决方案(因为决策可能会显著改变后续决策)
另一个选择是使用回溯。尝试一个决定,看看结果如何(最后评估代表人数)。然后,在返回时,还可以尝试其他决策。当代表人数超过迄今为止看到的最小人数时,您可能会离开决策分支。不幸的是,在最坏的情况下,这可能会导致指数级运行时间。但您只需在大小相同的圆圈重叠的情况下进行决策。如果不出现这种情况,则r通常,回溯可能是一个很好的选择,它可以保证您获得全局最优的解决方案
请记住,您的列表是经过排序的。当您搜索特定半径的圆时,不必搜索整个列表。代码中有几个地方可以通过这一事实加以改进。并且,如前所述,使用加速结构可以更快地评估重叠查询。我将算法分为两部分-repres动态检测和堆栈构建,其中堆栈构建基本上将每个圆与代表关联,形成堆栈
最后一部分很简单。迭代每个圆并将其与能量最小的代表关联(可能是最接近的一个)。使用加速数据结构(如网格或kd树)来增强此类查询
第一部分要难得多。事实上,它看起来是NP难的,虽然我不能证明它。但是让我们从一开始
按大小降序排列圆是一个好主意。如果第一个圆(最大半径)没有与相同半径的圆重叠,它显然应该具有代表性。在这种情况下,请从列表中删除(或标记)每个重叠圆。在另一种情况下,您必须决定重叠圆中的哪一个(半径相等的)选择
在您的代码中,您使用一个简单的启发式(重叠圆的数量)来决定选择哪个圆。根据您的数据和用例,这可能是一个有效的选项。一般来说,这可能并不总是导致最佳解决方案(因为决策可能会显著改变后续决策)
另一个选择是使用回溯跟踪。尝试一个d