我想提出以下算法:
输入是无符号整数。 输出是无序无符号整数对的数组的大小,当乘以时,给出一个小于或等于输入的数字。
我有一个天真的实现工作,但它对我的目的来说太慢了(compl.O(n ^ 2),如果我错了请纠正我)。我的问题是:如何让它更快?
#include <iostream>
using namespace std;
bool notInYet(int t[][1], int mi, int ma, int m) {
bool val = true;
for(int i = 0; i < m; i++)
if(t[i][0] == mi && t[i][1] == ma)
val = false;
return val;
}
int main() {
int n, m;
int t[100000][1];
cin >> n;
m = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j*i <= n && j <= i; j++) {
if(notInYet(t, j, i, m)) {
t[m][0] = j;
t[m][1] = i;
//cout << "t[" << m << "] = (" << t[m][0] << ", " << t[m][1] << ")" << endl;
m++;
}
}
}
cout << m << endl;
return 0;
}
答案 0 :(得分:4)
我认为应该是这样的 - 伪代码:
int counter = 0;
for int i = 1 to sqrt(input), i++ {
if (input % i == 0) counter++;
}
如果你需要唯一的对,计数器是一个答案,否则你需要乘以2(如果输入%sqrt(输入)== 0则需要乘以1)
答案 1 :(得分:1)
如果我正确阅读@ jauser的算法没有得到你想要的。
如果目标是5,则对是(1,1)(1,2)(1,3)(1,4)(1,5)(2,2)。所以答案是6.他的算法将产生1,因为5 mod 1 == 0,但不是mod 2.
通常,如果目标是n
,那么您知道(1,k)是从1到n的所有k的计数对。这些中有n - 1 + 1 = n。现在你有(2,k)k从2到楼(n / 2)(跳过1,因为你的对是无序的)。这些中有n / 2-2 + 1。通过(j,k)继续这个j = floor(sqrt(n))。这是伪代码
count = 0;
for j in 1 .. floor(sqrt(n))
count += floor(n / j) - j + 1;
也许甚至还有一些聪明的系列解决方案可以将其用于恒定的时间计算。
我错过了什么问题吗?
答案 2 :(得分:0)
嗯,你花了很多时间有效地计算每个i
的以下内容:
j= n/i;
因此,如果你这样做,你将复杂性降低到O(n
)。由于列表在(i, j)
时包含(j, i)
和i!=j
,因此您可以将其减半,但这不会降低整体复杂性。