*思考题将1、2、3、4、5、6、7、8、9九个数字分成以下三种带分数形式之一,每个数字只能用一次,使得该分数刚好等于一个整数。
N=X+XXXX/XXXX,N=X+XXXXX/XXX,N=XX+XXXX/XXX
例如:100=3+69258/714=81+5643/297(原书上写的是81+5648/297,错误)求所有满足条件的表示形式。(参考答案:某些自然数没有这种表示形式,如:1、2、3、4、15、18等。此外整数100有11种满足条件的表示形式;89的表示形式最多,共有36种;三种形式中,最大可表示的整数为794。)
*问题分析与算法设计基本思路是先构造数字不重复的分子,再从剩下的数字中构造一个加数,最后由构造分子和加数剩下的数字构造数字不重复的分母,然后判断和是不是整数,如果是,则打印出来。每一种形式的运算量都比较大,所以把他们各自写成一个完整的程序。3个程序之间的修改主要在:数位,判断条件,循环结束条件。
#include <stdio.h> #include <stdbool.h> bool CheckNum(int number); bool CheckDiv(int number); int main() { int i,j,k,l,m,n,num,den,inte,sum,count=1; int a[2][9]={1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,0,0}; int b[4]; for(n=1;n<17;n++) //N=X+XXXX/XXXX,N的最大值为9+8765/1234<17 { for(num=1234;num<=9876;num++) { if(!CheckNum(num)) continue; //检查分子的正确性,无重复数字且不含0 for(j=1,i=0;i<4;i++) { k=num/j%10; //给分子的每一位的标志位置1,从个位开始 a[1][k-1]=1; j=10*j; } //这时已经用掉了4个数 for(i=0;i<9;i++) { if(a[1][i]==0) { inte=a[0][i]; //从剩下的5个数中取一个数做为加数,并把它的标志位置1 a[1][i]=1; for(k=0,j=0;k<9;k++) //再把剩下的4个数字存到数组b中 { if(a[1][k]==0) { b[j]=a[0][k]; j++; } } for(j=0;j<4;j++) //用数组b中的4个数字来组成除数 { for(k=0;k<4;k++) { for(l=0;l<4;l++) { for(m=0;m<4;m++) { den=1000*b[j]+100*b[k]+10*b[l]+b[m]; if(!CheckDiv(den)) continue; //有重复就重新构造除数 sum=inte+num/den; if(num%den==0&&n==sum) { printf("[%d] %d=%d+%d/%d\n",count++,sum,inte,num,den); } } } } } a[1][i]=0; //选下一个数作为加数,把这个加数的标志位置0,留用于构造除数 } } for(i=0;i<9;i++) //重新给所有数字的标志位置0,准备开始下一轮循环 { a[1][i]=0; } } } return 0; } bool CheckNum(int number) //检查被除数的正确性 { int temp,i,j,k,a[4]; for(k=1,i=0;i<4;i++) { temp=number/k%10; if (temp==0) { return false; //如果某一位出现0,则找下一个数 } k=10*k; a[i]=temp; } for(i=0;i<4;i++) //检查是否有数字重复 { for(j=i+1;j<4;j++) { if(a[i]==a[j]) return false; //有重复,返回false } } return true; //未出现0且数字不重复,返回true } bool CheckDiv(int number) //检查除数的正确性 { int temp,i,j,k,a[4]; for(k=1,i=0;i<4;i++) { temp=number/k%10; k=10*k; a[i]=temp; } for(i=0;i<4;i++) //检查是否有数字重复 { for(j=i+1;j<4;j++) { if(a[i]==a[j]) return false; //有重复,返回false } } return true; //未出现0且数字不重复,返回true }