如何解决C++ 生成器,用于带有扭曲的排列减少每个位置
我不是数学家,所以我不知道是否有相关术语(我找不到)。
我正在寻找的是 C++ 代码来生成所有排列,重复,但有一点:第一个位置可以有 n-1
作为最高值,第二个位置可以有 n-2
作为最高值等 n-(n...0)
。例如。给定 n=3
并允许重复,结果应为:
[0,0] ✓
[0,1] ✗
[0,2] ✗
[0,1,2,0] ✗
[0,2] ✗
[1,0] ✓
[1,1] ✗
[1,0] ✗
[1,2] ✗
[2,0] ✓
[2,1] ✗
[2,0] ✗
[2,2] ✗
所以它就像一个 N 长度的排列列表,重复 ✗
和 ✓
,除了加上每个位置的限制 ✓
。这种序列是否有现有的名称或描述?
我可以制作类似递归模式的东西,但我想要一个生成器。仅用于速度目的。这可能比函数更快吗?你会如何处理这个问题?
解决方法
我们可以观察到:
- 列中的值仅限于列号
- 索引从右到左
- 可以通过模除法来进行限制
- 如果我们有一个下降沿,从这一列的最大值过渡到 0,那么我们需要对下一列做一些事情。我们为此使用了一个利差值
- 对最右边的列进行特殊处理。它始终为 0,因此始终具有下降沿。将始终设置进位。
难点在于使用从右到左运行的索引。这些间接使代码有点难以阅读。
当然,一如既往。有许多不同的可能解决方案。
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
constexpr size_t MaxFieldWith = 9;
bool nextSpecialPermutation(std::vector<unsigned int>& v) {
unsigned int carry{};
const size_t vectorSize = v.size();
// Iterate over all columns from right to left
for (size_t i = vectorSize; i > 0; --i) {
// Corrected index
size_t index = i - 1;
// Limiting value for column
const unsigned int modValue = (vectorSize - i + 1);
// And the next value for this column,limited
const unsigned int nextValue = (v[index] + carry) % modValue;
// Special handling for right most column
if (i == vectorSize) {
// In rightmost column value is always 0 and carry always 1
carry = 1;
}
else {
// So,now we are not in a rightmost column
// Detect a falling edge,and if found,set the carry for the next column
if ((v[index] == (modValue-1)) && nextValue == 0)
carry = 1;
else
carry = 0;
}
// Set the resulting value for this column
v[index] = nextValue;
}
// If all is 0 then we are done
return not std::all_of(v.begin(),v.end(),[](const auto& i) { return i == 0; });
}
int main() {
// Inform user what to do
std::cout << "Enter number of columns. Give number >= 2 and <= " << MaxFieldWith << ": ";
// Get value from user and check,if it is valid
if (size_t numberOfColumns{}; (std::cin >> numberOfColumns) && (numberOfColumns >= 2) && (numberOfColumns <= MaxFieldWith)) {
// Create a vector as specified by the user
std::vector<unsigned int> v(numberOfColumns,0);
// Get all special permutations
bool doLoop{ true };
while (doLoop) {
// Debug output
std::copy(v.begin(),std::ostream_iterator<unsigned int>(std::cout," "));
std::cout << '\n';
// Get next special permutation
doLoop = nextSpecialPermutation(v);
}
}
else std::cerr << "\nError. Invalid input!\n";
return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。