分享

C 之循环嵌套

 长沙7喜 2018-04-16

    4.12  S=1!+2!+3!+....+10!

   分析:这个问题是求10以内自然数的阶乘之和,可以用for循环来实现。程序结构如下:

   for(i=1;i<=10;++i)

   {  

     (1)i阶乘的值存到t    //t=i!

      (2)累加ts中;       //s+=t

   }

   显然根据以上结构,通过10次的循环可以求出1!,2!,…10!,并不断累加起来,求出s。而求t=i!,又可以用一个for循环来实现:

   t=1;

   for (j=1;j<=i;++j)

       t*=j;

因此整个程序为:

#include

using namespace std;

int main (){

 int t,s;

 s=0;

 for(int i=1;i<=10;++i)

   {

   t=1;

   for (int j=1;j<=i;++j)           //i!

     t*=j;

     s+=t;                           //累加i!

   }

 cout<

 return 0;

}

以上程序是一个for循环的嵌套。这种方法是比较容易想到的,但实际上对于求i!,我们可以根据求出的(i-1)!乘上i即可得到,而无需重新从1再累乘到i

因此程序可改为:

#include

using namespace std;

int main ()

{

 int t=1,s=0;

 for(int i=1;i<=10;++i)

 {

   t*=i;                           //t为上一个数的i-1的阶乘值,再乘以i即为i!

   s+=t;                           //累加i!

 }

 cout<

 return 0;

}

显然第二个程序的效率要比第一个高得多。第一个程序要进行1+2+3++10=55次循环,而第二程序进行10次循环。若题目中求的是1+2++1000!,则两个程序的效率区别更明显。

4.13  一个炊事员上街采购,用500元钱买了90只鸡,其中母鸡一只15,公鸡一只10元,小鸡一只5元,正好把钱买完。问母鸡,公鸡,小鸡各买了多少只?

【分析】设母鸡i,公鸡j,则小鸡为90-i-j,15*i+ 10* j+(90-i-j)*5=500,显然一个方程求两个未知数是不能直接求解。必须组合出所有可能的i,j值,看是否满足条件。这里i的值可以是033j的值可以050。源程序如下:

#include   

using namespace std;

int main ()

{

 int k;

 for (int i=0;i<=33;++i)                      //枚举母鸡的数量

 for (int j=0;j<=50;++j)               //枚举公鸡的数量

 {

   k=90-i-j;

   if (15*i+10*j+k*5==500)

   {

     cout<<'母鸡有'<,'<<'公鸡有'<,'<<'小鸡有'<'<

   }

 }

 return 0;

}

4.14  利用for循环语句输出图4-1中的三角形。

                                     *

                                     **

                                     ***

                                     ****

                                     *****

#include   

using namespace std;

int main ()

{

 for (int i=1; i<=5; ++i)             //控制行数

 {

   for (int j=1; j<=i; ++j)           //输出一行中的*

   cout<<'*';

   cout<换行

 }

 return 0;

}

4.15   100999中的水仙花数。若三位数ABCABC=A3+B3+C3,则称ABC为水仙花数。

例如15313+53+33=1+125+27=153,则153是水仙花数。

【分析】根据题意,采用三重循环来求解。由于循环次数一定,用for循环最为简单。程序如下:

#include

#include                            //调用setw函数需注明使用该库

using namespace std;

int main()

{

   for (int a=1; a<=9; ++a)

     for (int b=0; b<=9; ++b)

        for (int c=0; c<=9; ++c)

           {

             if (a*a*a+b*b*b+c*c*c==a*100+b*10+c)

              cout<函数控制输出场宽

           }

   return 0;

}

运行结果:

153370371407

同时也可以采用一个for循环来求解,表面上看好像优于三重循环,实际上却比上面的程序效率低,请同学们自己分析。

程序如下:

#include

#include

using namespace std;

int main()

{

  int a,b,c;

  for (int m=100; m<=999; ++m)

   {

      a=m/100;                              //m的百位

      b=(m%100)/10;                    //m的十位

      c=m%10;                       //m的个位

      if (a*a*a+b*b*b+c*c*c==m)

        cout<

   }

  return 0;

}

4.16   输出100200中所有的素数。

分析:我们可对100-200之间的每一个整数进行判断,若它是为素数,则输出。而对于任意整数i,根据素数定义,我们从2开始,到sqrti),找i的第一个约数,若找到第一个约数,则i必然不是素数。

程序如下:

#include  

#include                            //Dev C++中可调用数学函数库cmath

using namespace std;

int main ()

{

  intx;

  for(int i=100;i<=200;++i)

  {

    x=2;

    while(x<=floor(sqrt(i))&&(i%x!=0))    //floor为取整函数,需调用math.h

    x=x+1;                       //在枚举的范围内并且没有出现约数则继续枚举

    if ( x>floor(sqrt(i)))

      cout<

  }

 return 0;

}

4.17  输出所有形如aabb的四位完全平方数(即前两位数字相等,后两位数字也相等)。

【分析】

分支和循环结合在一起时威力特别强大:我们枚举所有可能的aabb,然后判断它们是否为完全平方数。注意,a的范围是19b可以是0。主程序如下:

   for (a=1; a<=9; a++)

     for (b=0; b<=9; b++)

       if (aabb是完全平方数) printf('%d\n',aabb);

另一个思路是枚举平方根x,参考程序如下:

#include

int main()

{

         intn=0,hi,lo;

         for(int x=1 ;  ; ++x)                //可以直接从x=32开始枚举

         {

                   n=x*x;

                 if(n<1000) continue;

                 if(n>9999) break;

                 hi= n/100;

                   lo= n%100;

                   if(hi/10 == hi%10 && lo/10 == lo%10) printf('%d\n',n);

         }

         return0;

}

4.18  阶乘之和

   输入n,计算S=1! + 2! + 3! + … + n!的末6(不含前导0)n<=106 n!表示前n个正整数之积。

   样例输入:10

   样例输出:37913

【分析】

   这个任务并不难,引入累加变量S之后,核心算法只有一句话:for (i=1;i<=n;i++) S+=i!。不过C++语言并没有阶乘运算符,所以这句话只是伪代码,而不是真正的代码。事实上,我们还需要一次循环来计算i!for (j=1;j<=i;++j) factorial*=j;。代码如下:

#include

int main()

{

         intn,s=0;

         scanf('%d',&n);

         for(int i=1;i<=n;++i)

         {

                   intfactorial=1;

                   for(int j=1;j<=i;++j)

                     factorial*=j;

                   s+=factorial;            

         }

         printf('%d\n',s%1000000);

         return0;

}

    注意累乘器factorial(英文阶乘的意思)定义在循环里面。换句话说,每执行一次循环体,都要重新声明一次factorial,并初始化为1(想一想,为什么不是0)。因为只要末6位,所以输出时对106取模。

n=100时,输出-961703,直觉告诉我们:乘法溢出了。这个直觉很容易通过输出中间变量法得到验证,但若要解决这个问题,还需要一点数学知识。试一下n=106时输出什么?更会溢出,但是重点不在这里。事实上,它的速度太慢!让我们把程序改成每步取模的形式,然后加一个计时器,看看它到底有多慢。

#include

#include

int main()

{

         constint MOD=1000000;

         intn,s=0;

         scanf('%d',&n);

         for(int i=1;i<=n;++i)

         {

                   intfactorial=1;

                   for(int j=1;j<=i;++j)

                   factorial=(factorial*j%MOD);

                   s=(s+factorial)%MOD;             

         }

         printf('%d\n',s);

         printf('Timeused= %.2lf\n',(double)clock()/CLOCKS_PER_SEC);

         return0;       //输出时间包含键盘输入的时间,建议用文件输入输出,后面章节介绍文件

}

   这个程序真正的特别之处在于计时函数clock()的使用。该函数返回程序目前为止运行的时间。这样,在程序结束之前调用它,便可获得整个程序的运行时间。这个时间除以常数CLOCKS_PER_SEC之后得到的值以为单位。

   输入100000,按Enter键,系统迟迟不输出答案,原因在于程序中重复进行了多次阶乘运算,浪费了大量时间,具体优化方法请参考例4.12

【上机练习4.4

1、求s=11+22+33+..+NN

2、求s=1+1/2!+1/3!++1/10!

3、输入一个整数,若是素数,输出“YES”,否则输出“NO

4、任给一个自然数n,求出这个自然数不同因数的个数。

  如:n=6时,因为1236这四个数均是6的因数,故输出为total=4

5、输入一列图形(字母金字塔)

                   a

                 a  b

              a   b   c

                .            .

          a b  c ……  y  z

6、把一张一元钞票换成一分,二分和五分的硬币,每种至少一枚。问有哪几种换法?

7、百鸡问题:一只公鸡值5元,一只母鸡值3元,而1元可买3只小鸡。现有100元钱,想买100只鸡。问可买公鸡、母鸡、小鸡各几只?

8、某人想将手中的一张面值100元的人民币换成10元、5元、2元和1元面值的票子。要求换正好40张,且每种票子至少一张。问:有几种换法?应适当考虑减少重复次数。

9、有一堆100多个的零件,若三个三个数,剩二个;若五个五个数,剩三个;若七个七个数,剩五个。请你编一个程序计算出这堆零件至少是多少个?

10、编写一程序,验证角谷猜想。所谓的角谷猜想是:“对于任意大于1的自然数n,若n为奇数,则将n变为3*n+1,否则将n变为n的一半。经过若干次这样的变换,一定会使n变为1。”

11、哥德巴赫猜想(任何充分大的偶数都可由两个素数之和表示)。将4-100中的所有偶数分别用两个素数之和表示。输出为:

4=2+2

6=3+3

100=3+97


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多