2D 点的排列

Permutations of 2D points

本文关键字:排列 2D      更新时间:2023-10-16

我想探索 2d 点的所有排列(2D 数组中的 x, y 坐标)我的 2d 点结构是:

struct pos_t {
    int x; int y; 
    pos_t(){x = 0 ; y = 0;} 
    pos_t(int X, int Y){x=X; y=Y;}
    pos_t(pos_t const & r) {x = r.x; y=r.y;}
    pos_t& operator=(pos_t const & r) {x = r.x; y=r.y; return *this;}
    bool operator < ( pos_t& p2)
    {
        return (x+y) < (p2.x+p2.y);
    }
    friend ostream& operator << (ostream &o, const pos_t& p)
    {
        return o << "(" << p.x << "," << p.y << ")";
    }
};

使用pos_t向量称为 treasurePos ( vector<pos_t> ),我使用下面的代码来迭代其他不同的排列并显示每个排列。

    do {
        copy(begin(treasurePos), end(treasurePos), ostream_iterator<pos_t>(cout, " -> "));
        cout << endl;
    } while ( std::next_permutation(begin(treasurePos),end(treasurePos)) );

但是在我的向量中有以下pos_t元素:(0,2) 和 (1,0)我只得到一种排列:(0,2) -> (1,0) ->

我期望有:

(0,2) -> (1,0) -> 
(1,0) -> (0,2) -> 

另一个例子,有 4 个点,我只得到 2 个置换:

(1,3) -> (2,2) -> (3,0) -> (3,1) -> 
(1,3) -> (2,2) -> (3,1) -> (3,0) -> 

你有什么想法吗?

当新排列在字典上不大于旧排列时,next_permutation false

由于您的排序说(1,0)小于(0,2),序列{(1,0), (0,2)}在字典上小于{(0,2), (1,0)},并且立即false next_permutation

同样的原因在你的四点例子背后。

如果要遍历所有排列,则应首先对序列进行排序。

在 molbdnil 答案之上。要获得所有排列,应对初始集进行排序。所以,这应该可以解决问题。

std::sort(begin(treasurePos), end(treasurePos));
do {
    copy(begin(treasurePos), end(treasurePos), ostream_iterator<pos_t>(cout, " -> "));
    cout << endl;
} while ( std::next_permutation(begin(treasurePos),end(treasurePos)) );

最后,我找到了为什么即使打电话给sort,我也永远不会得到所有的排列(见我的答案......),但再次感谢您的帮助。

在给next_permutation打电话之前,所有提到打电话给std::sort的答案都是正确的(这就是为什么我对大多数答案投了赞成票)。但实际上,这里最重要的是要注意lexicographic顺序取决于您使用的比较运算符。

默认参数是bool operator < ( ... ),但对于我提供的实现(见下文),(1,3)等于(3,1)。

bool operator < ( pos_t& p2)
{
    return (x+y) < (p2.x+p2.y);
}

这就是为什么我永远不会得到排列(即对于 N 个不同的元素,我们得到 N! 排列)

pos_t的正确运算符是:

bool operator < ( pos_t const & p) const
{
  return (x < p.x) || ((x == p.x) && (y < p.y));
}

现在我们可以对所有排列进行排序、循环和收集。

std::sort(begin(treasurePos), end(treasurePos));
do {
  vector<pos_t> c;
  copy(begin(treasurePos), end(treasurePos), back_inserter(c));
  copy(begin(c), end(c), ostream_iterator<pos_t>(cout, " -> "));
  cout << endl;
  treasure_order.push_back(c);
} while ( std::next_permutation(begin(treasurePos),end(treasurePos)) );
cout << "we stored " << treasure_order.size() << " path to get all the treasure (=nbTreasure! = " << fact((int)treasurePos.size()) << ")" << endl;

为了使 std::next_permutation 给出所有排列,您的初始向量应该在循环之前使用相同的比较器进行排序。

从 cplusplus.com:

将范围 [第一个、最后一个) 中的元素重新排列到下一个按字典顺序排列的更大排列中。

可以根据它们在词典上相互比较的方式对不同的排列进行排序;第一个这样的排序可能排列(将字典上较小的排列与所有其他排列进行比较的排列)是按升序排列的所有元素排序的排列,而最大的排列的所有元素都按降序排序。

如果函数可以确定下一个更高的排列,它将重新排列元素并返回 true。如果这是不可能的(因为它已经处于最大可能的排列),它会根据第一个排列(按升序排序)重新排列元素并返回 false。

所以基本上,如果你想让它工作,起始排列必须是最小的