我有一个值为{"Soa", "8", "m", "4", "8"}
我想从大小为n
的数组中打印所有排列而不重复(但在上面的向量中允许重复,如“8”),以指定大小k
。我已经搜索过这方面的解决方案,但在这种情况下无法找到。
目前的代码是:
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
int main()
{
std::vector<std::string> arr = { "Soa", "4", "m", "8", "8" };
std::sort(arr.begin(), arr.end());
do {
for(auto& i: arr)
std::cout << i;
std::cout << '\n';
} while(std::next_permutation(arr.begin(), arr.end()));
}
此代码仅打印矢量大小的所有排列(n=k
),因此它打印出我需要的内容,但n=5
。我想要的是指定n
,例如n=2
生成那些排列(打印它们的顺序无关紧要):
48
4Soa
4m
84
88
8Soa
8m
Soa4
Soa8
Soam
m4
m8
mSoa
编辑:由Nathan联系起来的解决方案不起作用,它将84与48相同。仍在寻找解决方案。
答案 0 :(得分:1)
这个简单的函数在执行时间上并不是最佳的,但它的速度相当快,并且在程序员时间内绝对有效。它通过循环排列来构造部分排列,但是跳过不改变k元素前缀的排列。矢量必须在开头排序;否则事情就会破裂。
> 2017-05-15 1
> 2017-05-12 3
> 2017-05-10 4
该函数取决于template<typename BidiIt>
bool next_partial_permutation(BidiIt first, BidiIt middle, BidiIt last) {
std::reverse(middle, last);
return std::next_permutation(first, last);
}
按字典顺序递增顺序生成排列的事实。因此,它可以直接从具有给定k前缀的第一个置换到具有该前缀的最后一个置换,只需通过从位置k开始反转向量。
(具有给定k前缀的第一个排列具有从位置k开始排序的元素;最后一个具有以相反顺序排序的元素;因此反转这些元素意味着下一次调用next_permutation
将产生下一个前缀。)
该功能是从this answer复制粘贴的,但我不认为这些问题足够相似,可以作为副本。
以下是如何使用它的示例。应该为程序提供值next_permutation
作为其第一个命令行参数,然后是向量的k
元素。 (它在启动之前对向量进行排序,因此您不需要确保对命令行参数进行排序。)
n
示例输出(live on coliru)
int main(int argc, char** argv) {
size_t k = std::atoi(argv[1]);
std::vector<std::string> words(argv + 2, argv + argc);
std::sort(words.begin(), words.end());
do {
for (size_t i = 0; i < k; ++i) std::cout << words[i];
std::cout << '\n';
} while (next_partial_permutation(words.begin(), words.begin() + k, words.end()));
return 0;
}