主题:求解阿克曼函数问题.急!!!!!!
			 joky
				 [专家分:120]  发布于 2006-06-01 12:31:00
 joky
				 [专家分:120]  发布于 2006-06-01 12:31:00							
			定义阿克曼递归函数:
ACK(0,n)=n+1         n>=0
ACK(m,0)=ACK(m-1,1)        m>=1
ACK(m,n)=ACK(m-1,ACK(m,n-1))      m,n>0 
当输入m=3,n=11(或n>11)或m=4(或m>4),n=1(或n>1)时就不能输出计算结果, 就会溢出,请问各位高手,怎么解决这个溢出问题呀?
						
					 
		
			
回复列表 (共10个回复)
		
								
				沙发
				
					 rickone [专家分:15390]  发布于 2006-06-01 14:14:00
rickone [专家分:15390]  发布于 2006-06-01 14:14:00				
				给我一个计算范围,才好确定存储范围.这样函数是递归定义的,又没要你用递归写程序.
							 
						
				板凳
				
					 joky [专家分:120]  发布于 2006-06-01 15:59:00
joky [专家分:120]  发布于 2006-06-01 15:59:00				
				
不好意思,让各位久等了,我刚下课.
好的,它的计算范围就是能输入m能输入10以上吧.谢谢.
							 
						
				3 楼
				
					 zyxdna [专家分:1250]  发布于 2006-06-01 18:09:00
zyxdna [专家分:1250]  发布于 2006-06-01 18:09:00				
				ACK(0,n)=n+1         n>=0
ACK(m,0)=ACK(m-1,1)        m>=1
ACK(m,n)=ACK(m-1,ACK(m,n-1))      m,n>0
ACK(0,0)=1,ACK(0,1)=2,ACK(0,2)=3,ACK(0,3)=4,ACK(0,4)=5,ACK(0,5)=6
ACK(1,0)=2,ACK(1,1)=3,ACK(1,2)=4,ACK(1,3)=5,ACK(1,4)=6,ACK(1,5)=7
在m=3,n=11应该还不至于溢出的
#include<stdio.h>
int ack(int m,int n)
{
     int num;
     if(m==0)
         return n+1;
     if(m>0&&n==0)
     {
         num=ack(m-1,1);
         return num;
     }
     if(m>0&&n>0)
     {
          num=ack(m-1,ack(m,n-1));
          return num;
     }
}
main()
{
     int m,n,c;
     scanf("%d,%d",&m,&n);
     printf("ack(%d,%d)=",m,n);
     printf("%d\n",ack(m,n));
     while(1);
}
ack(3,11)=16381
ack(3,12)=ack(2,16381)=32765
后面的就不敢保证了
							 
						
				4 楼
				
					 joky [专家分:120]  发布于 2006-06-01 18:29:00
joky [专家分:120]  发布于 2006-06-01 18:29:00				
				这是我写的程序,跟你写的也没什么差别.结果也是输不出(3,11)的结果,我调试了你的程序,也是输不出结果来,已经溢出.
如果改变VC6.0中默认的stack size大小的话就能输出,不过这不是我们所想要的.
#include<iostream.h>
long int count=0;
long int ACK(int m, int n) 
{ 
    long int temp; 
    count++;
    if (m == 0)  
        return (n + 1); 
    else if (n == 0)  
        return ACK(m - 1, 1); 
    else
    { 
        temp = ACK(m, n - 1); 
        return ACK(m - 1, temp); 
    } 
}
int main(int argc, char* argv[])
{
    int m,n;
    cin>>m>>n;
    cout<<ACK(m,n)<<endl;
    cout<<"共调用 "<<count<<" 次!"<<endl;
    return 0;
}
							 
						
				5 楼
				
					 zouyu1983 [专家分:1670]  发布于 2006-06-02 09:48:00
zouyu1983 [专家分:1670]  发布于 2006-06-02 09:48:00				
				#include <stdio.h>
int main()
{
    int value[25];
    int i,m,n;
    value[0] = 5;
    
    for (i=1; i<25; i++)
    {
        value[i] = value[i - 1] * 2 + 3;
    }
    
    while (scanf("%d%d", &m, &n) != EOF)
    {
        switch(m)
        {
        case 0: printf("%d\n", n + 1);
                break;
        case 1: printf("%d\n", n + 2);
                break;
        case 2: printf("%d\n", 3 + 2 * n);
                break;
        case 3: printf("%d\n", value[n]);
                break;
        default:break;
        }
    }
    return 0;
}
此程序通过FZU OJ的测试,仅供参考
							 
						
				6 楼
				
					 zouyu1983 [专家分:1670]  发布于 2006-06-02 09:49:00
zouyu1983 [专家分:1670]  发布于 2006-06-02 09:49:00				
				A函数增长速度是惊人的,用递归分治是不可能解决的,动态规划可以
可以分析A函数的规律,改为直接求解,oj上就有一题类似的
首先,递归深度太深,可能导致堆栈溢出,复杂度太大,可能导致tls, 反正,肯定过不了OJ的测试
							 
						
				7 楼
				
					 joky [专家分:120]  发布于 2006-06-02 20:45:00
joky [专家分:120]  发布于 2006-06-02 20:45:00				
				
是呀,由于它的增长速度太快,用递归是很容易溢出的,不过如果改变默认的堆栈大小的话就能计算出m=4,n=1,不过都要等很久才能看到结果.以前听说有人自己写堆栈实现了m=5,n=7,真是强,
							 
						
				8 楼
				
					 rickone [专家分:15390]  发布于 2006-06-02 23:30:00
rickone [专家分:15390]  发布于 2006-06-02 23:30:00				
				不好意思,我一开始看错了,6楼说DP可以求?不知道具体算法如何.7楼,自己写栈不能从时间上省下来,同样要等好久(太久甚至就是不可能)
							 
						
				9 楼
				
					 joky [专家分:120]  发布于 2006-06-03 00:14:00
joky [专家分:120]  发布于 2006-06-03 00:14:00				
				
呵呵,也是,不过至少那样可以自己控件堆栈的大小,而不用去更改默认的堆栈大小,那你有什么好的算法吗?
							 
						
				10 楼
				
					 xfcyjhb [专家分:0]  发布于 2007-12-11 16:13:00
xfcyjhb [专家分:0]  发布于 2007-12-11 16:13:00				
				
虽然计算机不能求出A(3,10) A(3,11)以及以后的阿克曼函数,但是我已经求出了A(3,n) A(2,n), A(1,n)的数学通项
A(1,n)=n+2
A(2,n)=2n+3
A(3,n)=2的(n+3)次方 减3
而A(4,1)=2的16次方 减3
A(4,2)=2的(2的16次方) 减3
A(4,3)=2的[2的(2的16次方)] 减3
而A(4,n)就是2的2的2的...(n个2)16次方 减3
算一下A(4,2)就知道有多大了, 而阿克曼函数又是递归函数,每算一个阿克曼数就需要把前面的每一个数算一遍,可见算的次数有多少了
							 
									
			
我来回复