紫皮书 - 第2章 循环结构程序设计

第二章 循环结构程序设计

2.1 for循环

例题

输出1,2,3\(\cdots\) \(\cdots\) n的值

程序2-1

#include<iostream>
using namespace std;
int main()
{
   int n;
   cin>>n; 
   for(int i=0;i<=n;i++)
        cout<<i<<endl;
   return 0;
}

提示:尽量缩短变量的定义范围,避免在其他地方调用而修改内容。

例题2-1 aabb

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

程序2-2

#include<iostream>
#include<math.h>
using namespace std;
int main()
{
    for(int a=1;a<=9;a++)
        for(int b=0;b<=9;b++)
        {
           int n=a*1100+b*11;           //在这里使用n,因此在这里定义
           int m=floor(sqrt(n)+0.5);   /*   函数floor(x)返回不超过x的最大整数
                                            这里不能写成if(sqrt(n)==floor(sqrt(n))),浮                                                  点数计算会产生误差 
		                                     一般改成四舍五入,即floor(x+0.5)    */
		   if(m*m==n)                        
		     cout<<n<<endl;                 
        }
      return 0;
}

程序2-3

#include<iostream>
using namespace std;
int main()
{
   for(int i=1;;i++)
   {
       int n=i*i;
       if(n<1000) continue;
       if(n>9999) break;
       int hi=n/100;
       int lo=n%100;
       if(hi/10==hi%10 && lo/10==lo%10)
            cout<<n<<endl; 
   }
   return 0;
}

2.2 while循环和do-while循环

例题2-2 3n+1问题

对于任意大于1的自然数\(n\),若\(n\)为奇数,则将\(n\)变为3\(n\)+\(1\),否则变为\(n\)的一半。输入\(n\),输出变换的次数。

\(n\) $\leq$109。经过若干次这样的变换,一定会使n变为1。

程序2-4

#include<iostream>
using namespace std;
int main()
{
     long n;                //当n过大时,很容易乘法溢出,要将n设为长整型。
	 int count=0;           //count是用来充当计数器的变量 
     cin>>n;
     while(n>1)
     {
          if(n%2==1) n=n*3+1;
          else n/=2;
          /*
          cout<<n<<endl;      当出现错误,观察无法找出错误时,可以输出中间结果查错。
          */
          count++;
     }
     cout<<count<<endl;
     return 0;
}

例题2-3 近似计算

计算\(\frac{\pi}{4}\) =1-\(\frac{1}{3}\)+\(\frac{1}{5}\)-\(\frac{1}{7}\)+\(\cdots\) \(\cdots\),直到最后一项小于10-6

【分析】因为在计算完一项之后才知道它是否小于10-6,所以循环终止是在计算之后,这时候就适合用do-while循环。

程序2-5

#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
     double  sum=0;
     for(int i=0; ;i++)
     {
        double  term=1.0/(2*i+1);
        if(i%2==0) sum+=term;
        else  sum-=term;
        if(term<1e-6) break;
     }
     cout<<setiosflags(ios::fixed)<<setprecision(6)<<sum<<endl; 
     return 0;
}

程序2-6

#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
   double sum=0;
   double term;
   int i=0; 
   do
   {
        term=1.0/(2*i+1);
        if(i%2==0) 
            sum+=term;
        else  
            sum-=term;
        i++;
        //cout<<term<<endl;
    }while(term>1e-6);
    cout<<setiosflags(ios::fixed)<<setprecision(6)<<sum<<endl;
     return 0;
}

2.3 循环的代价

例题2-4 阶乘之和

输入 \(n\),计算 \(S=1!+2!+3!+\cdots+n!\) 的末六位(不含前导0)。\(n\)$\leq\(10^6^,\)n$$!$表示前 \(n\)个正整数之积。

程序2-7
#include<iostream>
using namespace std;
#include<time.h>
int main()
{
    const int MOD=1000000;
    int n,s=0;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int f=1;
        for(int j=1;j<=i;j++)
            f=(f*j%MOD);         //在每步计算之后对n取余,结果不变。 
        s=(s+f)%MOD;                 
         //cout<<s<<" ";         //n>25之后六位不变,因为25!后六位为零 
    }
    cout<<s<<endl;
    cout<<"Time used="<<(double)(clock()/CLOCKS_PER_SEC)<<endl;
    return 0;
}

提示:可以使用time.h和clock()函数获得程序的运行时间。常数CLOCKS_PER_SEC和操作系统相关,请不要直接直接使用clock()的返回值,而应总是除以CLOCKS_PRE_SEC。

2.4算法竞赛中的输入输出框架

提示:在Windows下输入完毕后先按Enter键,再按Ctrl+Z键,最后再按Enter键,即可结束输入。在Linux下,输入完毕后按Ctrl+D键即可结束输入。

提示:变量在未赋值之前的值是不确定的。特别的,他不一定等于0。

  • 使用输入输出重定向,只需在main函数的入口处加入一下两条语句:

    freopen("input.txt","r",stdin);

    freopen("output.txt","w",stdout);

程序2-8 (重定向版)

#include<iostream>
using namespace std; 
#define LOCAL
#define INF 1000000000
int main()
{
	
    #ifdef LOCAL
      freopen("data.in","r",stdin);     //重定向的部分写在了#ifdef和#endif中
      freopen("data.out","w",stdout);
    #endif
    
    int x,n=0,min=INF,max=-INF,s=0;
    cin>>x;
    while(x!=0)
    {
        s+=x;
        if(x<min) min=x;
        if(x>max) max=x;
    /*
    cout<<"x="<<x<<"mn="<<min<<"max="<<max<<endl;
    */
    n++;
    cin>>x;
    }
   cout<<min<<" "<<max<<" "<<(double)s/n<<endl;
   return 0;
}

程序2-9 (fopen版)

#include<stdio.h>
#define INF 1000000000
int main()
{
    FILE *fin,*fout;
    fin=fopen("data.in","rb");
    fout=fopen("data.out","wb");
    int x,n=0,min=INF,max=-INF,s=0;
    while(fscanf(fin,"%d",&x)==1)
    {
        s+=x;
        if(x<min) min=x;
        if(x>max) max=x;
        n++;
    }
    fprinf(fout,"%d%d%.3f\n",min,max,(double)s/n);
    fclose(fin);
    fclose(fout);
    return 0;
}

知识点:

2.5注解与习题

习题1 水仙花数

输出100~999中的所有水仙花数。若3位数ABC满足\(ABC\)=\(A\)3+\(B\)3+\(C\)3,则称其为水仙花数。

#include<iostream>
using namespace std;
int main()
{
	//int a,b,c; 
    for(int i=100;i<=999;i++)
    {
        int a=i%10;
        int b=i/10%10;
        int c=i/100;
        if(i==a*a*a+b*b*b+c*c*c)
            cout<<i<<endl; 
    }
    return 0;
}

习题2 韩信点兵

韩信点兵每次让队伍以三人一队,五人一队,七人一队,只要看队尾的人数就可以知道总人数,总人数不超过一百。输入包含多组数据,每组数据包含3个非负整数 \(a\) , \(b\) , \(c\) ,表示每种队形排尾的人数( \(a\) ❤️, \(b\) <5, \(c\) <7),输出总人数的最小值(或报告无解)。已知总人数不小于10,不超过100。输入到文件结束为止。

#include<iostream>
using namespace std;
int main()
{
	int x,y,z;   //定义最后一排的人数 
	int n;
	while(cin>>x>>y>>z)
	{
		for(n=10;n<=101;n++)
		{
			if(n==101)
			{
				cout<<"no answer"<<endl;
				break;
			}
			if(n%3==x && n%5==y && n%7==z)
			{
				cout<<n<<endl;
			       break;
			} 
		}
	}
	return 0;
}

习题3 倒三角

输入正整数n<=20,输出一个n层的倒三角形。

#########

#######

​ #####

​ ###

​ #

#include<iostream>
using namespace std;
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<i;j++)
            cout<<" ";
        for(int k=2*(n-i)+1;k>=1;k--)
            cout<<"#";
        cout<<endl;
    }
    return 0;
}

习题4 子序列的和

输入两个正整数\(n\)<\(m\)<106,输出,保留五位小数。输出包含多组数据,结束标记为n=m=0。提示:本题有陷阱。

#include<iostream>
using namespace std;
int main()
{
	long long n,m;   //当输入n,m较大时,容易溢出
	double sum=0.0;
	while(cin>>n>>m)
	{
		double sum=0.0;
		for(long long i=n;i<=m;i++)
			sum+=1.0/(i*i);
		cout<<sum<<endl;    
	}
	return 0;
 } 

习题5 分数化小数

输入正整数\(a\), \(b\), \(c\); 输出\(a\) / \(b\)的小数形式,精确到小数点后 \(c\) 位。\(a\), \(b\) $\leq$106, \(c\)$\leq$100。输入包含多组数据,结束标记为a=b=c=0。

#include<iostream>
using namespace std;
#include<iomanip> 
int main()
{
	double a,b,c;
	while(cin>>a>>b>>c)
	{
		cout<<setiosflags(ios::fixed)<<setprecision(c)<<(double)(a/b)<<endl;
	}
	return 0;
}

习题6 排列

用1,2,3 \(\cdots\) \(\cdots\) 9组成3个三位数\(abc\), \(def\) , \(ghi\) 。每个数字恰好用一次,要求 \(abc\) : \(def\) : \(ghi\)=1:2:3。

#include<iostream>
using namespace std;
int add=0,mul=1;
void return13(int num)
{
	int x,y,z;
	x=num/100;
	y=num/10%10;
	z=num%10;
	add+=x+y+z;         //计算三位数字的和
	mul*=x*y*z;         //计算三位数字的乘积
}

int main()
{
	for(int i=123;i<=329;i++)
	{
		int j=i*2;
		int k=i*3;
	
		return13(i);
		return13(j);
		return13(k);
		
		if(add==45&&mul==362880)         //1~9的和为45,9!=362880
		   cout<<i<<":"<<j<<":"<<k<<endl;
		   
		add=0;
		mul=1; 
	}
	return 0;
 }

posted @ 2019-09-17 19:47  mandala  阅读(204)  评论(0编辑  收藏  举报