我正在尝试这里提到的Bytelandian金币问题 - http://www.codechef.com/problems/COINS/这是其中一个解决方案 -
#include <stdio.h>
long int a[30][19]; //1
long int recur(long int n, int i, int j);
int main()
{
long int n;
int i, j;
while (scanf("%lld", &n) != EOF)
{
for (i = 0; i < 30;i++)
for (j = 0; j < 19; j++)
a[i][j] = 0;
long int v = recur(n, 0, 0);
printf("%lld\n", v);
}
return 0;
}
long int recur(long int n, int i, int j)
{
if (n <12 ) //2
return n;
else if (!a[i][j])
{
long int t = recur(n / 2, i + 1, j) + recur(n / 3, i, j + 1) + recur(n / 4, i + 2, j);
a[i][j] = t;
}
return a[i][j];
}
在这段代码中,我无法理解两点 - 1 - 数组a [30] [19]的大小,它基于输入数字的最大值可被2或3整除的最大次数,它们使用一些对数基数2或3公式来查找.Can有人请解释这个公式,这是一些数学属性,如果是,我在哪里可以找到更多的信息。 2 - 停止递归n&lt; 12条件被使用,因为12以下的所有数字将具有与自身相等的值作为最大值。我无法理解它是如何被发现的。我的意思是如果我替换了它,他们如何发现12是限制值原来的复发功能我得到了错误的答案 -
long int recur(long int n, int i, int j)
{
if ((n == 0) || (n == 1) || (n == 2) )
return n;
else if (!a[i][j])
{
long int t = recur(n / 2, i + 1, j) + recur(n / 3, i, j + 1) + recur(n / 4, i + 2, j);
a[i][j] = n> t ? n : t;
}
return a[i][j];
}
如果有人请解释上述2点,我将不胜感激
答案 0 :(得分:0)
i 的上限来自条件 2 i ≤10 9 (次数10 9 可以除以2直到达到1等于1的次数可以乘以2直到达到10 9 ;求解 i 得出i≤log 2 (10 9 )≅29.9。
另一种看待它的方法是将10 9 表示为二进制数111011100110101100101000000000 2 ;这个数字有30个数字,每个整数除以2得到一个数字减去(删除最右边的数字),所以在29个分区之后我们到达1.
正如JohnH在上面的评论中正确指出的那样, i 的最大值仍然低于29,因为递归不会下降到 n = 1 ,而是停在 n&lt; 12 。
大约相同的是 j 的上限和除以3. 10 9 作为三元数是2120200200021010001 3 ;这个数字有19位数字;在17个整数除以3之后,我们到达21 3 = 7,递归停止。
要知道12以下的所有数字都等于其最高交换金额,我们可以简单地尝试一下:
n n/2 n/3 n/4 sum of the 3 exchanged coins 1 0 0 0 0 2 1 0 0 1 3 1 1 0 2 4 2 1 1 4 5 2 1 1 4 6 3 2 1 6 7 3 2 1 6 8 4 2 2 8 9 4 3 2 9 10 5 3 2 10 11 5 3 2 10 12 6 4 3 13
我们看到12是交换时产生高于其自身值的最低数字。
如果我用这个替换原来的复现功能我就错了 回答 -
从 n = 509607936 上,您会收到“错误答案”,因为long int t
等溢出到负值。奇怪的是,对于原始recur
函数,此错误由另一个错误补偿,即BLUEPIXY指出的错误转换规范%lld
。通过使用类型a
定义recur
,t
,v
和unsigned long int
并使用适当的转换规范%lu
,可以更正该计划。< / p>