我如何在C 中制作算法,以在不重复的情况下查找集合的变化(即n元素,选择k)
How can I make an algorithm in C++ for finding variations of a set without repetition (i.e. n elements, choose k)?
例如,(n = 3, k = 2)
,我已经设置了{1, 2, 3}
,我需要我的算法才能找到: {1, 2}, {1, 3}, {2, 1}, {2, 3}, {3, 1}, {3, 2}
。
我能够使用next_permutation
制作算法,但是n = 10, k = 4
的工作速度非常慢(这是我需要的)。
这是我的代码:
#include <iostream>
#include <algorithm>
#define pb push_back
using namespace std;
int main() {
vector <int> s = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int k = 4; // (n = 10, k = 4)
map <string, int> m; // To check if we already have that variation
vector <string> v; // Variations
do {
string str = "";
for (int i = 0; i < k; i++) str += to_string(s[i]);
if (m[str] == 0) {
m[str] = 1;
v.pb(str);
}
} while (next_permutation(s.begin(), s.end()));
return 0;
}
如何制作更快的算法?
此代码生成了n项中k项的排列,以简单的态度包装成整数(因此153对应于(1,5,3))
void GenArrangement(int n, int k, int idx, int used, int arran) {
if (idx == k) {
std::cout << arran << std::endl;
return;
}
for (int i = 0; i < n; i++)
if (0 == (used & (1 << i)))
GenArrangement(n, k, idx + 1, used | (1 << i), arran * 10 + (i + 1));
}
int main()
{
GenArrangement(5, 3, 0, 0, 0);
}
123124125132134135142143145152153154213214215231234235241243245251253254312314315321324325341342345351352354412413415421423425431432435451452453512513514521523524531532534541542543
您可以在每个子集上迭代bitmask。
for(unsigned int i = 0; i < (1<<10);i++)
当您不需要便携式代码时,您可以使用
__builtin_popcount(int)
至少在GCC中使用X86处理器在二进制表示中获得1s的数量。
for(unsigned int i = 0; i < (1<<10);i++) {
if(__builtin_popcount(i) == 4) { //Check if this subset contains exactly 4 elements
std::string s;
for(int j = 0; j < 10; j++) {
if(i&(1<<j)) { //Check if the bit on the j`th is a one
s.push_back(to_string(j));
}
}
v.push_back(s);
}
}
slowness是由于生成所有n!即使仅需要一小部分,排列也是如此。您的复杂性在O(n! * k log n)附近,其中 o(k log n)是对所有排列查询std::map
的复杂性的上限。
MBO的答案仅限于9个值(1..9)。即使将其扩展到打印更长的值,它们仍然受到位数的限制(通常为INT为31,如果有UINT64_T可用,则为64位)。
这里是:
void print_permutations_impl(std::ostream & out, std::vector<int> & values,
unsigned k, std::vector<int> & permutation_stack)
{
if (k == permutation_stack.size())
{
const char* prefix = "";
for (auto elem: permutation_stack) {
out << prefix << elem;
prefix = ", ";
}
out << 'n';
return;
}
auto end_valid = values.size() - permutation_stack.size();
permutation_stack.push_back(0);
for (unsigned i=0 ; i < end_valid; ++i) {
permutation_stack.back() = values[i];
std::swap(values[i], values[end_valid - 1]);
print_permutations_impl(out, values, k, permutation_stack);
std::swap(values[i], values[end_valid - 1]);
}
permutation_stack.pop_back();
}
void print_permutations(std::ostream & out, const std::vector<int> & values, int k)
{
std::vector<int> unique = values;
std::sort(unique.begin(), unique.end());
unique.erase(std::unique(unique.begin(), unique.end()),
unique.end());
std::vector<int> current_permutation;
print_permutations_impl(out, unique, k, current_permutation);
}
它以n = 100和k = 2的次秒速度工作
//finds permutations of an array
#include<iostream>
#include<vector>
using namespace std;
inline void vec_in(vector<unsigned>&, unsigned&);
inline void vec_out(vector<unsigned>&);
inline void vec_sub(vector<vector<unsigned>>&, vector<unsigned>&, unsigned&);
int main(){
unsigned size;
cout<<"SIZE : ";
cin>>size;
vector<unsigned> vec;
vec_in(vec,size);
unsigned choose;
cout<<"CHOOSE : ";
cin>>choose;
vector<vector<unsigned>> sub;
vec_sub(sub, vec, choose);
size=sub.size();
for(unsigned y=0; y<size-2; y++){
for(unsigned j=0; j<choose-1; j++){
vector<unsigned> temp;
for(unsigned i=0; i<=j; i++){
temp.push_back(sub[y][i]);
}
for(unsigned x=y+1; x<size; x++){
if(temp[0]==sub[x][choose-1]){break;}
vector<unsigned> _temp;
_temp=temp;
for(unsigned i=j+1; i<choose; i++){
_temp.push_back(sub[x][i]);
}
sub.push_back(_temp);
}
}
}
cout<<sub.size()<<endl;
for(unsigned i=0; i<sub.size(); i++){
vec_out(sub[i]);
}
return 0;
}
inline void vec_in(vector<unsigned>& vec, unsigned& size){
for(unsigned i=0; i<size; i++){
unsigned k;
cin>>k;
vec.push_back(k);
}
}
inline void vec_out(vector<unsigned>& vec){
for(unsigned i=0; i<vec.size(); i++){
cout<<vec[i]<<" ";
}
cout<<endl;
}
inline void vec_sub(vector<vector<unsigned>>& sub, vector<unsigned>& vec,
unsigned& size){
for(unsigned i=0; i<vec.size(); i++){
//if(i+size==vec.size()){break;}
vector<unsigned> temp;
unsigned x=i;
for(unsigned k=0; k<size; k++){
temp.push_back(vec[x]);
x++;
if(x==vec.size()){x=0;}
}
sub.push_back(temp);
}
}
这不会像您在示例中那样以相反的顺序打印。通过一次逆转数组来打印,您将完全得到答案!
背后的想法是:
1.说您有5个数字:1 2 3 4 5,然后您一次选择3个数字,然后
2.按序列顺序找到子阵列:
1 2 3
2 3 4
3 4 5
4 5 1
5 1 2
3.这些将是长度为n
的第一个n子阵列4.现在,从第1个子阵列中获得1,从第二个子阵列中获得3,4,然后从这3个元素中进行另一个子阵列,然后从第三个子阵列中获得4,5,然后做同样的事情。不要从最后两个子阵列中获取元素,因为此后元素将开始重复。
5.现在从第一个子阵列中取1,2,从第二个子钻中拿出4个子阵列,并从第三个子钻中取5个,然后制作一个数组
6.将所有这些阵列推回您拥有的数组列表。
7.从第二个子阵列中执行相同的模式以前的情况下,工作子ARR是第一个,我们没有开始从第四个子数组中获取元素!]
使用std::next_permutation
和bitset
(当前std::prev_permutation
具有词典订单和std::vector<bool>
而不是std::bitset
,以允许动态大小):
template <typename T>
void Combination(const std::vector<T>& v, std::size_t count)
{
assert(count <= v.size());
std::vector<bool> bitset(count, 1);
bitset.resize(v.size(), 0);
do {
for (std::size_t i = 0; i != v.size(); ++i) {
if (bitset[i]) {
std::cout << v[i] << " ";
}
}
std::cout << std::endl;
} while (std::prev_permutation(bitset.begin(), bitset.end()));
}
demo
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 如何在不使用 C++ 中的数组或函数的情况下查找 N 位数字的所有排列
- 在无法访问向量的情况下查找迭代器的末尾
- 在不进行排序的情况下查找数组中n个最小值的索引
- 在给定元素在螺旋上的位置的情况下,在二维数组中查找元素
- 在没有查找表的情况下计算大数的位长度
- 如何在给定任意数量的整数的情况下创建一个唯一键?并使用该键存储,然后从地图中查找
- 在没有比较运算符的情况下查找 2 个数字之间的最小值
- 为什么在这种情况下不考虑依赖于参数的查找?
- 我如何在C 中制作算法,以在不重复的情况下查找集合的变化(即n元素,选择k)
- 在给定长度无限循环的情况下,在Collatz猜想中查找起始数的代码
- 在没有字符串或字符帮助的情况下查找数字的反面(例如:2500 reverse 0025)
- 如何在不使用目录的情况下在磁盘上查找文件
- 如何在不使用if语句的情况下查找数组中的最大值和最小值
- 如何在不复制或查找的情况下获取 const 字符串流缓冲区的长度?
- using声明如何减少可用于在没有 ADL 的情况下查找的名称
- 在没有第三方工具/项目的情况下,在 MFC C++发布版本中查找内存泄漏
- C/C++宏,用于在不使用三元运算符的情况下查找两个数字的最大值
- 如何在不遍历内容的情况下查找文件中的字符数
- 如何在不读取整个文件的情况下查找文件中字符串的长度