我正在尝试在C中编写一个算法,对于给定的自然数n
,它会找到(x,y)
对的数量x,y
,其中{{1}}是整数,
x 2 + y 2 < = n 2
我能够通过两个for循环执行此操作,但是,这似乎不是最理想的。这个问题最有效的方法是什么?
答案 0 :(得分:3)
你不需要两个循环。只需循环遍历x,然后就可以计算y
,因为x
和n
都已知。
答案 1 :(得分:3)
只需要在边界处找到点,即对于每个给定的x,最大y_max s.t. x ^ 2 + y_max ^ 2< = n。那么给定x的有趣对的数量是2 * y_max + 1。对于x = 0,我们有y_max = n。对于x> 0,我们还必须考虑具有-x的对。这导致以下代码:
int pairCnt = 2*n+1; /* pairs (0,-n), (0,-n+1), ..., (0,n) */
int n2 = n*n;
for (int x=1; x<=n; ++x)
{
int y_max = (int)sqrt(n2-x*x);
pairCnt += 2*(2*y_max+1); /* (+/-x,-y_max), ..., (+/-x,y_max) */
}
使用以下算法可以避免使用sqrt:
int pairCnt = 2*n+1; /* pairs (0,-n), (0,-n+1), ..., (0,n) */
int n2 = n*n;
for (int x=1, y_max=n; 1; ++x)
{
if (y_max*y_max > n2-x*x)
--y_max;
if (x > y_max) break;
pairCnt += 2*(2*y_max+1); /* (+/-x,-y_max), ..., (+/-x,y_max) */
}
int s = 2*x-1; /* side length of maximal inscribed square */
pairCnt = 2*pairCnt - s*s;
第二种算法的第一个想法是,当x增加时,y_max将最大减少1,只要y_max> x(即我们沿着圆的内部,半径为n从(0,n)开始直到我们越过第一个中位数y = x)。当我们将计数点的副本加上90°(即到目前为止发现的点数的两倍)时,我们将计算最大内切正方形内的点数两次。
这是n = 3的一种可视化。 *
标记有趣集合(x*x+y*y > n*n=9
)之外的对。数字标记到目前为止计算有趣集合(x*x+y*y <= n*n=9
)内的对的频率。
before loop after loop after doubling result
---- ---- ---- ----
432101234 432101234 432101234 432101234
4 ********* ********* ********* *********
3 ****1**** ****1**** ****1**** ****1****
2 **00100** **11111** **22222** **11111**
1 **00100** **11111** **22222** **11111**
0 *0001000* *0111110* *1222221* *1111111*
-1 **00100** **11111** **22222** **11111**
-2 **00100** **11111** **22222** **11111**
-3 ****1**** ****1**** ****1**** ****1****
-4 ********* ********* ********* *********
答案 2 :(得分:0)
如果你实现了一个函数int int_sqrt (int n)
,它返回sqrt(double n)
的整数部分,那么你可以使用这个函数只用一个循环来处理它。但整数平方根仅存在于C ++中,因此您必须通过将结果转换为int
来实现C中的一个
编辑: 这是个主意:
int x=0,result=0;
while ( (n-(x*x)) >=0){
result += int_sqrt ( n-(x*x) ) +1;
x++;
}
如果您接受所有整数,包括0来制作您的情侣。