《算法竞赛入门经典(第二版)》习题解答——第二章

Posted Q.Y71

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法竞赛入门经典(第二版)》习题解答——第二章相关的知识,希望对你有一定的参考价值。


文章目录


一、习题2-1 水仙花数(daffodil)

输出100~999中的所有水仙花数。若3位数ABC满足ABC=A3+B3+C3,则称其为水仙花数。例如153=13+53+33,所以153是水仙花数。

#define _CRT_SECURE_NO_WARNING
#pragma warning(disable : 4996)
#include<stdio.h>
int main()

    int a, b, c;
    for (int i = 100; i <= 999; i++) 
    a = i / 100;
    b = i / 10 % 10;
    c = i % 10;
    if (i == a * a * a + b * b * b + c * c * c)
        printf("%d是水仙数\\n", i);
        
    return 0;

二、习题2-2 韩信点兵(hanxin)

相传韩信才智过人,从不直接清点自己军队的人数,只要让士兵先后以三人一排、五人 一排、七人一排地变换队形,而他每次只掠一眼队伍的排尾就知道总人数了。输入包含多组 数据,每组数据包含3个非负整数a,b,c,表示每种队形排尾的人数(a<3,b<5,c< 7),输出总人数的最小值(或报告无解)。已知总人数不小于10,不超过100。输入到文件 结束为止。
样例输入:
2 1 6
2 1 3
样例输出:
Case 1: 41
Case 2: No answer

题解1

#include<stdio.h>
int main()

    int a,b,c,n,i = 1;
    scanf("%d%d%d",&a,&b,&c);
    for(n = 10;n < 101;n++)
        if(n % 3 == a && n % 5 == b && n % 7==c)
            i = 0;
            break;
        
    
    if(i)
        printf("No answer\\n");
    else
        printf("总人数 = %d\\n",n);
    
    return 0 ;

解析

用i标志来解决输出问题

题解2

#include<stdio.h>
int main()
   int a,b,c,i,n=0;
    freopen("2-2 datain.txt","r",stdin);//需要提前在cpp文件同一目录下建立txt文件作为scanf的读取路径
    freopen("2-2 dataout.txt","w",stdout);
    while(scanf("%d%d%d",&a,&b,&c)==3)
	   
		++n;
		for(i=10;i<=100;i++)
	   
			if(i%3==a && i%5==b && i%7==c)
			
				printf("Case %d: %d\\n",n,i);
				break;
			
						
	   
	   if(i>100) printf("No answer\\n");	   		
	
	
	return 0;


解析

此代码运用文件读写方式。

关于文件结束,在参考不同的答案时有人根据其标志为EOF,所以while的条件为while (scanf ("%d%d%d",&a,&b,&c) != EOF),但此题中我用了重定向的方法,故循环条件为while(scanf("%d%d%d",&a,&b,&c)==3)。

三、习题2-3 倒三角形(triangle)

输入正整数n≤20,输出一个n层的倒三角形。例如,n=5时输出如下:

#include<stdio.h>
int main()

    int n;
    scanf("%d",& n);
    for (int i = 0; i < n; i++) 
      for (int j = 0; j < 2*n-1; j++) 
         if(j<i) printf(" ");
          if(j>=i&&j<2*n-i-1) printf("#");
        
      printf("\\n");     
    
        
    return 0;

四、习题2-4 子序列的和(subsequence)

输入两个正整数n<m<106,输出 1 n 2 + 1 ( n + 1 ) 2 + ⋯ + 1 m 2 \\frac1n^2+\\frac1(n+1)^2+\\cdots +\\frac1m^2 n21+(n+1)21++m21 ,保留5位小数。输入包含多组数据, 结束标记为n=m=0。提示:本题有陷阱。
样例输入:
2 4
65536 655360
0 0
样例输出:
Case 1: 0.42361
Case 2: 0.00001


#include<stdio.h>
int main()

    int n,m,temp;
    double s=0;
    scanf("%d%d",& n,&m);
    if (n > m) 
        temp = n;
        n = m;
        m = temp;
    
    for (int i = n; i <= m; i++) 
        s += 1.0 / i/i;  //1.0/(i*i)精度会溢出    
      
    printf("%.5lf",s);      
    return 0;


防止精度溢出也可以将n,m,i的类型直接定义为long long型

五、习题2-5 分数化小数(decimal)

输入正整数a,b,c,输出a/b的小数形式,精确到小数点后c位。a,b≤10^6,c≤100。输 入包含多组数据,结束标记为a=b=c=0。
样例输入:
1 6 4
0 0 0
样例输出:
Case 1: 0.1667

#include<stdio.h>
int main()

    int a,b,c;
    double s=0;
    scanf("%d%d%d",& a,&b,&c);
    s = a * 1.0 / b;
    printf("%.*lf\\n",c,s);      
    return 0;

printf的特殊用法printf("%*.*lf\\n",a,b,s);前面的**定义的是总的宽度,后边的是定义保留的小数位数

六、习题2-6 排列(permutation)

用1,2,3,…,9组成3个三位数abc,def和ghi,每个数字恰好使用一次,要 求abc:def:ghi=1:2:3。按照“abc def ghi”的格式输出所有解,每行一个解。提示:不必太动脑筋。

#include<stdio.h>
int main()

    int n,m,t;
    for (int i = 1; i <= 9; i++) 
        for (int j = 1; j <= 9; j++) 
            if (i == j)continue;
            for (int k = 1; k <= 9; k++) 
                if (i == j || i == k || j == k)continue;
                    n = i * 100 + j * 10 + k;
                    m = 2 * n;
                    t = 3 * n;
                int d = m / 100;
                int e = m / 10 % 10;
                int f = m % 10;
                int g = t / 100;
                int h = t / 10 % 10;
                int i = t % 10;
                if(d != e && d != f && d != g&& d != h&&d != i && e != f && e != g && e != h && e != i && f != g && f != h && f != i && g != h && g != i && h != i&&m<1000&&t<1000)
                printf("%d %d %d\\n", n, m, t);      
            
        
        
    return 0;

总结

文件输入题是硬伤!!
代码逻辑没有太大问题,但由于能力有限,部分代码不够简洁,会继续努力哒

算法竞赛入门经典第二版 第二章习题及思考题

enmmmmmm】  大部分好像除了最后一个思考题都很简单

代码如下

#include <iostream>
#include  <cstring>
#include   <cstdio>
#include    <cmath>

int main(){
    /*
    for(int i =100 ; i <= 999 ; i++)
    {
        int a = i/100;int c = i%10;int b = (i-a*100)/10;//水仙花数
        if( i == pow(a,3)+pow(b,3)+pow(c,3)) WA
        //if( i == a*a*a+b*b*b+c*c*c) //AC
            printf("%d=  %d^3 + %d^3 + %d^3
",i,a,b,c);
    }*/
    
    /*int a,b,c,kase=1;//2-2hanxin韩信
    while(scanf("%d%d%d",&a,&b,&c) == 3 )//3 5 7
    {
        int flag =0;
        printf("Case %d: ",kase++);
        a = a*70+b*21+c*15;
        while(a >= 105){
            a -= 105;
        }
        if(a <=10 || a>=100 )printf("No answer
");
        else printf("%d
",a );
        //for(int i = 10;i <= 100 ; i++)
        //    if(i%3==a && i%5==b && i%7==c)
        //        {printf("%d
",i);flag=1;}
        //if(!flag) printf("No answer
" );

    }*/
    /*
    int n;scanf("%d",&n);//2-3triangle倒三角形
    for(int i = n;i >= 1 ;i--)
    {
        for(int j = n-i  ;j > 0;j--)printf(" ");
        for(int j = i*2-1;j > 0;j--)printf("#");
        for(int j = n-i  ;j > 0;j--)printf(" ");
        printf("
");
    }*/
    /*int n,m;while( scanf("%d%d",&n,&m)==2 )
    {//2-4子序列的和 subsequence
        if(n == 0 && n == m)break;
        double ans = 0.0;
        for( int i = n ; i <= m;i++)
        {
            ans += (1.0/i)*(1.0/i); //直接1.0/(i*i)就炸
//sum += 1 / (((double)n + i) * ((double)n + i)); 
//在n较大时,((double)n + i) * ((double)n + i)会溢出,
//所以应该改成 1 / ((double)n + i) / ((double)n + i)
            //printf("i=%d ans=%.5lf
", i,ans);
        }printf("%.5lf
", ans);//printf("%u %u
", -1,-2);
    }*/
    /*

        int a,b,c,n,n1;
        while(scanf("%d%d%d",&a,&b,&c)==3 && (a||b||c)) 
            { 
                for(int count=0; ;count++) 
                    {
                     if(count) 
                         {
                         if(count<=c) 
                            printf("%d",n); 
                        else 
                            { 
                                if(n1=a/b >= 5) n++; 
                                printf("%d",n); 
                                break; 
                            } 
                        n=a/b; a=(a-n*b)*10; 
                        if(count == 1) std::cout<<"."; 
                         }    
                    }
            } 
    int a,b,c,kase=0,i;
    while(scanf("%d%d%d",&a,&b,&c)&&a&&b&&c){
        printf("Case %d: %d.",++kase,a/b);
        a%=b;
        for( i = 1; i < c; i++){
            printf("%d",a*10/b);
            a=a*10%b;
        }
    
        if( a*10%b*10/b >= 5) a*10/b++;
          printf("%d
",a*10/b);
    }*/
    /*
    int a,b,c;//2-5分数化小数 decimal
    while(scanf("%d%d%d",&a,&b,&c)==3 ){
        if( a== b && b==c && a==0)break;
        int aa[505],bb[505];
        aa[0] = a/b;
        aa[1] = a*10/b;

        for(int i=2; i <= c+1;i++)
        {
            bb[i] = a*10%b;
            aa[i] = bb[i]*10/b;
        }//printf("%d.",aa[0]);
        if(aa[c+1] >= 5 )aa[c] += 1;
        for(int i=c; i >= 1 ;i--)
            if(aa[i] == 10) 
                aa[i]-=10,aa[i-1]+1;
        printf("%d.",aa[0] );
        for(int i=1; i < c; i++)
            printf("%d",aa[i] );
        printf("%d
",aa[c]);
    }
    int a,b,c;while(scanf("%d%d%d",&a,&b,&c) == 3 && a){
            //if(a <= 1e+6 && b <= 1e+6 && c <= 200 && a != 0 && b != 0 && c != 0){
            printf("%.*lf
",c,(double)a / (double)b);
        //}    
    }*/
    /*for(int i=123; i <= 333; i++)
    {//排列
        bool aa[10]={false};
        int flag =0 ;
        aa[i/100] = aa[i/10%10] = aa[i%10]=true;
        int j = i*2; int k = i*3;
        aa[j/100] = aa[j/10%10] = aa[j%10]=true;
        aa[k/100] = aa[k/10%10] = aa[k%10]=true;
        for(int d= 1; d <= 9; d++)
        {
            if( aa[d] == false )
                {flag=1;break;}
        }
        if( !flag )
            printf("%d:%d:%d
", i,j,k);
    }
    int n;scanf("%d",&n);
    for(int i = 1; i <= n; i++)//for(int i = 2; i <= n; i+=2)
        printf("%d
", 2*i);*/
    double i = 0;
    for( i = 0; i != 10; i += 0.1)
    
        printf("%f", i);
    return 0;
}

至于最后一个思考题  浮点数陷阱

把 10 改成10.0 10.000000 啥的都没用 脑阔疼 搜了下发现了这个博客 http://blog.sina.com.cn/s/blog_6da76f9b0100yr8d.html

浮点数陷阱:
 
   之所以无限循环,那么就可以推断是for循环的条件始终成立,即 i 始终不等于10.
 
   是因为浮点数的原因. 我们把10改成10.0,结果仍然是无限循环.
 
   是浮点数的加法运算引起的.
 
   调用gdb输出中间结果来观察,发现 i 自加0.1后,并不是我们预想的等于0.1
 
   而是等于 0.10000000000000001.
 
   再往下执行几次,i 的值分别是0.20000000000000001.
 
                                          0.30000000000000004.      
 
                                          0.40000000000000002.
 
  所以程序不会终止  因为浮点数在进行小数运算的时候由于
 
   精度问题,会有很小的误差,然而用 = 或者 != 这样的运算符来比较,是会检测出这种
 
   误差的.所以导致结果的不正确. 
 
   将循环条件改为 i != 0.1 或者 i != 0.2时,程序能够正常运行,得到正常结果.但是当i != 0.3时,就是无限循环.显然,在我们的程序中,这种
 
   不确定的错误是不应该存在的.
 
   因此,在定义循环变量时,尽量采用int型及整数的加减.因为循环的本质意义就是  通过各种条件来控制语句重复运行次数.而这个次数本身就是整数.要实现小数的功能  尽量通过循环中的语句来实现. 

以上是关于《算法竞赛入门经典(第二版)》习题解答——第二章的主要内容,如果未能解决你的问题,请参考以下文章

《算法竞赛入门经典(第二版)》pdf

算法竞赛入门经典 第二版 1-3答案

算法竞赛入门经典(第二版)3-5谜题UVA277

算法竞赛入门经典(第二版)3-3数数字UVA1225

算法竞赛入门经典第二版 随笔1

算法竞赛入门经典第二版 竖式问题 P42