#define MIN -2147483648
long max(long x,long y)
{
long m=x;
if(y>x)
m=y;
return m;
}
long f(int x,int y,int **p)
{
long result;
if(x<0||y<0)
result = MIN;
else
if(x==0&&y==0)
result = p[0][0];
else
result = max(f(x-1,y,p),f(x,y-1,p))+p[x][y];
return result;
}
int main(void)
{
int n;
scanf("%d",&n);
int** p = (int **)malloc(n*sizeof(int*));
for(int i=0;i<n;i++)
{
p[i] = (int*)malloc(n*sizeof(int));
for(int j=0;j<n;j++)
scanf("%d",p[i]+j);
}
printf("haha\n");
printf("%ld\n",f(n-1,n-1,p));
return 0;
}
当我将10分配给n
时,效果很好。但是当我将{20}分配给n
时,没有结果。我用谷歌搜索它,我猜测错误可能是递归溢出。那么我该如何解决这个问题呢?
答案 0 :(得分:3)
你正在进行大量的递归调用。在每个级别,您将调用次数设置为先前级别的两倍。因此,当N为20时,您正在进行2 ^ 20 = 1048576个函数调用。这需要很长时间。
这些调用中的大多数都会反复重新计算相同的值。而是重新计算这些值,只计算一次。
这是一种非递归的方法:
long f(int x,int y,int **p)
{
long **p2;
int i, j;
p2 = malloc(sizeof(long *)*(x+1));
for (i=0;i<=x;i++) {
p2[i] = malloc(sizeof(long)*(y+1));
for (j=0;j<=y;j++) {
if (i==0 && j==0) {
p2[i][j] = p[i][j];
} else if (i==0) {
p2[i][j] = p2[i][j-1] + p[i][j];
} else if (j==0) {
p2[i][j] = p2[i-1][j] + p[i][j];
} else {
p2[i][j] = max(p2[i-1][j], p2[i][j-1]) + p[i][j];
}
}
}
return p2[x][y];
}
编辑:
如果您仍想要递归解决方案,则可以执行以下操作。如果尚未计算必要的值,则仅进行递归调用。
long f(int x,int y,int **p)
{
static long**p2=NULL;
int i, j;
if (!p2) {
p2 = malloc(sizeof(long*)*(x+1));
for (i=0;i<=x;i++) {
p2[i] = malloc(sizeof(long)*(y+1));
for (j=0;j<=y;j++) {
p2[i][j] = MIN;
}
}
}
if (x==0 && y==0) {
p2[x][y] = p[x][y];
} else if (x==0) {
if (p2[x][y-1] == MIN) {
p2[x][y-1] = f(x,y-1,p);
}
p2[x][y] = p2[x][y-1] + p[x][y];
} else if (y==0) {
if (p2[x-1][y] == MIN) {
p2[x-1][y] = f(x-1,y,p);
}
p2[x][y] = p2[x-1][y] + p[x][y];
} else {
if (p2[x][y-1] == MIN) {
p2[x][y-1] = f(x,y-1,p);
}
if (p2[x-1][y] == MIN) {
p2[x-1][y] = f(x-1,y,p);
}
p2[x][y] = max(p2[x-1][y], p2[x][y-1]) + p[x][y];
}
return p2[x][y];
}
答案 1 :(得分:0)
您没有指定使用的编译器。了解如何增加程序的堆栈大小。但是,即使你让n = 20工作,由于前面评论中提到的组合爆炸,也会有一个限制(可能离n = 20不远)。
对于n&gt; 0,每次调用f(n)调用f(n-1)两次。所以调用f(n)=调用2 * fn(n-1)
对于n = 20,即2 ^ 20个呼叫。每次调用返回一个long。如果long是8个字节= 2 ^ 3,那么堆栈上至少有2 ^ 23个字节。
修改强>
实际上,根据documentation,链接器控制堆栈大小。 您可以尝试增加堆栈大小并实现更高效的算法,如不同的答案所提出的
使用ld(GNU链接器)增加堆栈大小
- 筹码储备
- 堆栈保留,提交
指定要保留(并可选择提交)的内存字节数,以用作此程序的堆栈。默认值为2Mb保留,4K已提交。 [此选项特定于链接器的i386 PE目标端口]