C++ 选择没有重复的随机坐标?
我想在8x8板上选择随机坐标。x和y坐标只能是-8-6、-4、-2、0、2、4、6和8。我想为20个对象选择随机坐标,但我不希望任何两个对象具有相同的坐标。用C++编程离开!p> 每个坐标只有9个可能值,因此总共有81个可能点。最简单的解决方案是只列举所有可能的点,例如:在数组或向量中,然后随机选择20个C++ 选择没有重复的随机坐标?,c++,algorithm,random,C++,Algorithm,Random,我想在8x8板上选择随机坐标。x和y坐标只能是-8-6、-4、-2、0、2、4、6和8。我想为20个对象选择随机坐标,但我不希望任何两个对象具有相同的坐标。用C++编程离开!p> 每个坐标只有9个可能值,因此总共有81个可能点。最简单的解决方案是只列举所有可能的点,例如:在数组或向量中,然后随机选择20个 您可以随机选择20,方法是从0到80选取一个索引,将数组中的该元素与索引80交换,然后从0到79随机选取一个索引,与索引79交换,以此类推20次。然后数组的最后20个元素将是20个不同的随机点
您可以随机选择20,方法是从0到80选取一个索引,将数组中的该元素与索引80交换,然后从0到79随机选取一个索引,与索引79交换,以此类推20次。然后数组的最后20个元素将是20个不同的随机点。将劳伦斯算法放入程序。工作正常
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
//To store x and y coordinate of a point
struct Point
{
int x, y;
};
int main()
{
vector<Point> v;
Point p;
//Populate vector with 81 combinations.
for(int i = -8; i < 10; i += 2)
{
for(int j = -8; j < 10; j += 2)
{
p.x = i;
p.y = j;
v.push_back(p);
}
}
srand(time(NULL));
int lastIndex = 80;
for(int i = 0; i < 20; i++)
{
int randNum = rand() % (81-i);
//Swap to isolate chosen points.
std::swap(v[randNum], v[lastIndex-i]);
}
//Print chosen random coordinates
cout<<"Random points chosen are "<<endl;
for(int i = 61; i < 81; i++)
{
Point p = v[i];
cout<<p.x<<"\t"<<p.y<<endl;
}
}
将集合中的所有坐标对放入一个列表,并生成一个随机排列的列表,该列表中存在标准算法,如劳伦斯建议的算法。以排列的前20个元素为例。如果可以枚举电路板上的所有坐标,则可以使用任何采样算法。你在一个9x9的网格上;只需从[0,80]范围中选取20个值,然后将它们转换为栅格坐标:
// Say the number picked is "n"
int x = ((n % 9) - 4) * 2;
int y = ((n / 9) - 4) * 2;
您可以使用任何采样算法生成ns;例如,查看以下问题的答案
与显式生成点相比,这种方法的优点是可以在大型网格上节省大量内存和处理时间。如果它们真的很大,而您选择的是一个小的简单点,那么显而易见的算法也很好:只需选择一个随机点,如果您已经选择了,请重试。该算法的唯一问题是,如果选择集合的很大一部分,它可能会进行多次重试。例如,可以使用std::random\u shuffle,因为整数坐标数有限。所以,只需将这组向量/位置混洗一下。您还可以将自己的RNG作为函数对象传递给random_shuffle 例如:
#include <algorithm> //for copy and random_shuffle
#include <utility> //for pair and make_pair
#include <vector>
...
std::vector<std::pair<int, int> > coords;
std::vector<std::pair<int, int> > coords20(20);
for(int y=-8; y<=8; y+=2)
for(int x=-8; x<=8; x+=2)
coords.push_back(std::make_pair(x,y));
std::random_shuffle(coords.begin(), coords.end());
std::copy(coords.begin(), coords.begin() + 20, coords20.begin());
这是一个很好的解决方案,但它需要与集合大小成比例的内存。我有时想知道,当可能的坐标数达到天文数字时,是否有办法解决这个问题。如果集合中有一万亿个坐标对,而我们希望每个坐标对只访问一次,但顺序是随机的,那么我们该如何处理呢?只要你能枚举你的点并直接从序列号有效地计算出任意点的位置,你就可以使用任何有效的一维采样算法,例如Floyd的算法-请参阅我的答案了解更多详细信息。如果您要使用STL,为什么不同时使用std::random_shuffle?@Blastfurny:是的,但这在我的vc express版本中不可用。我有MSVC++express 2010,并且一直使用附带的STL。如果您有std::vector和std::swap,您应该可以使用STL的其余部分。@bastfrance:哦,对不起,当我键入std::,IDE时没有显示我,但它在那里。没问题。我非常喜欢STL,并尽可能地利用它。你可以用STL算法和lambda函数做很多事情。所以它实际上是一个9x9板。旁注:你解释的只是给不知道它的人起个名字。事实上,一旦你有了20个值,你就可以停止交换,因为这些值不会再改变了。@Joey:一旦你有了20个值,你就可以停止交换,这就是为什么我说……等等20次。