有效的方法来计算具有限制的唯一排列

问题描述

所以我知道有很多计算唯一排列的方法。 通常,在生成过程中应用限制要比事后删除限制要慢。 假设我有10个元素的向量。 举个例子:

std::vector<int> v = {7,5,16,8,1,7,3,25,109,8};

我有一个独特的限制,我知道我不允许连续使用相同的三个数字,因此任何地方包含{8,8}的所有排列都是无效的。 如果我有很多例如我假设20个元素,如果我跳过以{8,8}开头的所有排列,可以节省很多时间。

有什么办法可以有效地做这样的事情吗?我如何确定在什么时候增加检查每个排列的额外速度才有意义?

解决方法

在您的限制下,可以按顺序进行迭代,但是可以从第一个无效排列中跳过无效排列的块。

第一个无效排列形式

y y y 8 8 x x 8 x

y y y 8 8 8 x1 x2 x3,x1

因此您可以直接使用

进行最后一个无效排列

y y y 8 8 8 x3 x2 x1,x1

所以只需倒数最后一个数字即可。

bool is_valid(const std::vector<int>& v)
{
    auto it = std::find(v.begin(),v.end(),8);
    
    return v.end() - it >= 3 && (*it != *(it + 1) || *it != *(it + 2));
}

void go_to_last_invalid(std::vector<int>& v)
{
    auto it = std::find(v.begin(),8);
    std::reverse(it + 3,v.end());
}

int main()
{
    std::vector<int> v = {1,7,8,9,10};
    do {
        if (!is_valid(v)) { go_to_last_invalid(v); continue; }
        for (auto e : v) { std::cout << e << " "; } std::cout << std::endl;
    } while (std::next_permutation(v.begin(),v.end()));
}

Demo