我的老师要我编写一个获取整数值N的函数,并返回长度为2n的数组,并包含该值的skolem序列。
例如:function(4)将返回{4,2,3,2,4,3,1,1}
我不知道该怎么做。
答案 0 :(得分:1)
数字 n 的Skolem序列是一个大小为2× n 的整数序列,符合两个标准:
对于每个非负数 k &lt; n ,正好存在两个元素 s i ,以及 s 序列中的 j ,使 s i = s < sub> j = k
如果 s i = s j = k 和 i &lt; j 然后 j - i = k
请参阅http://mathworld.wolfram.com/SkolemSequence.html
基本上,这意味着您需要创建一个数字从1到n的序列,其中每个数字出现两次。要将序列转换为skolem序列,两个1必须彼此相邻,两个2必须在它们之间有一个数字,3个必须在它们之间有2个数字,依此类推。
这种算法比人们想象的要困难得多。最简单的方法是检查序列的每个排列,并返回第一个有效的排列。这是(2n)!复杂性,这是非常缓慢的。这是一个没有n的算法的参考!复杂: http://www.cs.mun.ca/~dchurchill/pdf/honours.pdf
我用C ++编写了朴素算法。这将为任何给定的输入生成Skolem序列。这个算法速度非常慢,但我希望你明白这一点:
#include<iostream>
#include<vector>
#include<algorithm>
void start(int num, std::vector<int>& v) { //creates the |2n| sequence
for(int i = 1; i<=num; i++) {
v.push_back(i);
v.push_back(i);
}
}
bool check(std::vector<int>& v) { //checks to see if sequence is a skolem sequence
for(int i = 1; i<=v.size()/2; i++) {
auto j = std::find(v.begin(), v.end(), i);
auto k = std::find(j+1, v.end(), i);
if(k-j != i) {
return false;
}
}
return true;
}
void skolem(int num, std::vector<int>& v) { //permutes the vector to find skolem sequences
start(num, v);
while(std::next_permutation(v.begin(), v.end())){
if(check(v))
break;
}
}
int main()
{
int num;
std::cin>>num;
std::vector<int> v;
skolem(num, v);
std::cout<<"found it"<<std::endl;
print(v);
}
此算法仅适用于小数(小于10)。如果您需要处理更大的序列,我建议您查看上面的链接。