数字黑洞求解问题

任意一个5位数,比如:34256,把它的各位数字打乱,重新排列,可以得到一个最大的数:65432,一个最小的数23456。求这两个数字的差,得:41976,把这个数字再次重复上述过程(如果不足5位,则前边补0)。如此往复,数字会落入某个循环圈(称为数字黑洞)。
比如,刚才的数字会落入:[82962, 75933, 63954, 61974] 这个循环圈。要求编写程序,找到5位数所有可能的循环圈,并输出。

这是某个比赛中的一个问题,我试着用c语言求了一下。大概思路就是:把五位数拆分,排序,求最大和最小数,求差,再判断是否落入了黑洞数的循环。

 

/****************************************
输出5位数的全部黑洞数 
*****************************************/
#include<stdio.h>
int Max_Min(int num);
void Find(int num);
int c[20]={0},k=0;        //这两个全局变量是为了查重 
void main()
{
    int num; 
    
    for(num=10000;num<99999;num++)
    {
        Find(num);
    }    
} 
/**********************************
函数名称:Max_Min
函数功能:把一个五位数的各位提取出来,
          重新组合成最大数和最小数,并求差 
参数:num--输入的五位数 
返回值:sub_result--最大数与最小数的差 
***********************************/ 
int Max_Min(int num)
{
    char i=0,j=0,t;
    int max=0,min=0,sub_result; 
    char a[5];
    for(i=0;i<5;i++)            //把各位数取出来,不足5位的补0 
    {
        a[i]=num%10;
        num=num/10;
    }
    for(i=0;i<=3;i++)            //从大到小排序 
        for(j=0;j<=3-i;j++)
        {
            if(a[j]<a[j+1])
            {
                t=a[j];
                a[j]=a[j+1];
                a[j+1]=t;
            }
        }
    for(i=0;i<=4;i++)
    {
        max=max*10+a[i];        //组成的最大的数 
    }
    for(i=4;i>=0;i--)
    {
        min=min*10+a[i];        //组成的最小的数 
    }
    sub_result=max-min;            //求差 
    return sub_result; 
}
/*********************************
函数名称:Find 
函数功能:判断输入的数是否有黑洞数,并输出
参数:num--输入的五位数 
**********************************/
void Find(int num)
{
    char i,j,m,flag=0;
    int b[100]; 
    b[0]=Max_Min(num);
    for(i=1;i<100;i++)                //测试前100个
    {
        b[i]=Max_Min(b[i-1]);         
        for(j=0;j<i;j++)
        {
            if(b[j]==b[i])
            {
                flag=1;
                for(m=0;m<20;m++)    //查看前面是否已经输出过 
                {
                    if(b[j]==c[m])
                    {
                        flag=0;
                        break;
                    }
                }
                break;
            }    
        }
        if(flag==1)                    //存在黑洞数并且前面没有输出过 
        {
            printf("%c",'[');
            for(;j<i-1;j++)
            {
                printf("%d%c",b[j],',');
                c[k++]=b[j];    
            }
            printf("%d",b[j]);
            c[k++]=b[j];
                
            printf("%c",']');
            printf("\n");
            return ;
        }
    }
}

这段程序很多不足之处,比如在对最大和最小数求差的时候,只求了100次,当然算出来结果也是对的,因为五位数的黑洞数都能在100次之内被检测出来,其实实际情况远远用不了100次。结果虽然对,但思路总归不严谨。下面给出一个用递归法求解的。

#include<stdio.h>
int Max_Min(int num);
void Find(int num);
int record1[50]={0},k=0;        //这两个全局变量是为了查重 
int record2[100],f;                //每次使用前清零 
void main()
{
    int num; 
    char m;
    for(num=10000;num<=99999;num++)
    {
        
        Find(num); 
        for(m=0;m<100;m++)            //由于是全局变量,在本次使用后清零 
        {
            record2[m]=0;
        }
        f=0;
    }    
} 
/**********************************
函数名称:Max_Min
函数功能:把一个五位数的各位提取出来,
          重新组合成最大数和最小数,并求差 
参数:num--输入的五位数 
返回值:sub_result--最大数与最小数的差 
***********************************/ 
int Max_Min(int num)
{
    char i=0,j=0,t;
    int max=0,min=0,sub_result; 
    char a[5];
    for(i=0;i<5;i++)            //把各位数取出来,不足5位的补0 
    {
        a[i]=num%10;
        num=num/10;
    }
    for(i=0;i<=3;i++)            //从大到小排序,冒泡法排序 
        for(j=0;j<=3-i;j++)
        {
            if(a[j]<a[j+1])
            {
                t=a[j];
                a[j]=a[j+1];
                a[j+1]=t;
            }
        }
    for(i=0;i<=4;i++)
    {
        max=max*10+a[i];        //组成的最大的数 
    }
    for(i=4;i>=0;i--)
    {
        min=min*10+a[i];        //组成的最小的数 
    }
    sub_result=max-min;            //求差 
    return sub_result; 
}
/*********************************
函数名称:Find 
函数功能:判断输入的数是否有黑洞数,并输出
参数:num--输入的五位数 
**********************************/
void Find(int num)
{
    char i,j,m;
    int n;
    n=Max_Min(num);
    for(i=0;i<f;i++)
    {
        if(n==record2[i])            //检测黑洞数 
        {
            for(j=0;j<50;j++)        //检测是否已经输出过 
            {
                if(n==record1[j])
                {    
                    return;            //前面已经输出过,退出函数 
                }
            } 
            printf("%c",'[');
            for(j=i;j<f-1;j++)                    //将黑洞数输出 
            {
                printf("%d%c",record2[j],',');
                record1[k++]=record2[j];        //记录,为下次输出查重 
            }
            printf("%d",record2[j]);
            record1[k++]=record2[j];            //记录,为下次输出查重
            printf("%c",']');
            printf("\n");
            
            return;                    //输出完毕,退出 
        }
    }
    record2[f++]=n;
    
    Find(n);        //递归调用 
}

这段代码用了递归调用,可以一直求最大值与最小值的差直到出现循环。这种思路就比前面的那种要好很多。输出结果如下:

当然这段代码还有些问题,虽然可以输出正确结果,但是效率不高,从10000检测到99999要把所有的5位数都检测一遍,很复杂。不过现在我还没想到更高效率的解法,以后努力吧。

 

posted @ 2014-01-17 11:04  The Pisces  阅读(1027)  评论(0编辑  收藏  举报