C++ 选择没有重复的随机坐标?

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个不同的随机点

我想在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个不同的随机点。

将劳伦斯算法放入程序。工作正常

#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次。