根据自然数序列创建序列:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
在第二步中删除每第二个号码:
1 3 5 7 9 11 13 15 17 19 21 23
在第3步中删除每3个号码(来自上一个序列):
1 3 7 9 13 15 19 21
在第4步中删除每第4个号码(来自上一个序列):
1 3 7 13 19
依此类推...... 现在,我们可以说,序列的第4个数字将是13。
定义和正确的解决方案是:http://oeis.org/A000960
我的任务是找到序列的第1000个成员。 我已经为此编写了一个算法,但我觉得它很慢(当我尝试使用第10,000个成员时需要大约13秒)。它的作用是:
我知道,number
每一步都会增加2
没有偶数。
在counters
数组中,我存储每个步骤的索引。如果数字是
xth步骤中的xth,我必须删除它,例如第3步中排名第5。和
我为下一步启动了一个计数器。
ArrayList<Long> list = new ArrayList<Long>(10000);
long[] counters = new long[1002];
long number = -1;
int active_counter = 3;
boolean removed;
counters[active_counter] = 1;
int total_numbers = 1;
while (total_numbers <= 1000) {
number += 2;
removed = false;
for (int i = 3; i <= active_counter; i++) {
if ((counters[i] % i) == 0) {
removed = true;
if (i == active_counter) {
active_counter++;
counters[active_counter] = i;
}
counters[i]++;
break;
}
counters[i]++;
}
if (!removed) {
list.add(number);
total_numbers++;
}
}
答案 0 :(得分:4)
您与OEIS的链接为我们提供了一些快速计算方法(公式等)
第二个实施:
function Flavius(n: Integer): Integer;
var
m, i: Integer;
begin
m := n * n;
for i := n - 1 downto 1 do
m := (m - 1) - (m - 1) mod i;
Result := m;
end;
P.S。算法是线性的(O(n)),n = 10000的结果是78537769
答案 1 :(得分:2)
这个问题不是NP难......
我有直觉O(n^2)
,链接证明了它:
Let F(n) = number of terms <= n. Andersson, improving results of Brun,
shows that F(n) = 2 sqrt(n/Pi) + O(n^(1/6)). Hence a(n) grows like Pi n^2 / 4.
它认为O(n^2)
不应该给n = 10000的15s。是的,有些东西不正确:(
修改:
我衡量了对counters
(n = 10000
)的访问次数,以便大致了解复杂性,我有
F = 1305646150
F/n^2 = 13.05...
您的算法介于O(n^2)
和O(n^2*(logn))
之间,因此您正在做正确的事情.... :)
答案 2 :(得分:1)
我刚刚失去了一小时的生命。我认为问题将变成NP难。而且我无法生成一个方程来计算j th 步骤中的i th 项。
除非有一些聪明的数学技巧可以在一步中生成最终解决方案,否则您的“暴力”解决方案似乎很好。但我认为没有。
从编程的角度来看,您可以尝试将初始数组作为链接列表,然后取消链接要删除的术语。这样可以节省一些时间,因为你不会每一步都重建你的列表。
答案 3 :(得分:1)
一种方法可能是保留您用来筛选的数字数组,而不是筛选的数字。基本上,如果要查找序列中的第N个值,则创建一个N个计数器的数组,然后遍历自然数。对于每个数字,循环遍历计数器,递增它们直到达到“最大”值,此时将该计数器设置为零并停止递增剩余的计数器。 (这表示在该计数器的步骤中删除当前数字。)如果您通过所有计数器而不删除当前数字,那么这是剩下的数字之一。
一些样本(Java)代码似乎与OEIS给出的序列匹配:
public class Test {
public static void main(String[] args) {
int N=10000;
int n=0;
long c=0;
int[] counters = new int[N];
outer: while(n<N) {
c++;
for(int i=0;i<N;i++){
counters[i]++;
if(counters[i]==i+2){
counters[i]=0;
continue outer;
}
}
// c is the n'th leftover
System.out.println(n + " " + c);
n++;
}
}
}
我相信这是在O(N ^ 3)中运行。