算法竞赛入门经典第二章习题解答

空扰寡人 提交于 2020-02-25 01:59:03

本章的题目需用文件输入输出,如果题目代号为abc,那么输入文件为abc.in,输出文件为abc.out。如果对文件操作不熟练,请尽量把fopen和freopen两种方法都尝试一下。

注:本次解答中前4题给出两种方法,第五题采用fopen方法,其余均采用重定向方法。

习题2-1 位数(digit)

问题描述:输入一个不超过10^9的正整数,输出它的位数。例如12735的位数是5.请不要使用任何数学函数,只用四则运算和循环语句实现。

重定向版:

#define LOCAL
#include<iostream>
#include<cstdlib>
#include<cstdio>
using namespace std;
int main()
{
    #ifdef LOCAL
      freopen("digit.in","r",stdin);
      freopen("digit.out","w",stdout);
    #endif // LOCAL
    int n,cnt=1;
    scanf("%d",&n);
    while(n/10)
    {
        cnt++;
        n/=10;
    }
    printf("位数:%d\n",cnt);
}

fopen版:

#include<stdio.h>
int main()
{
    FILE *fin,*fout;
    fin=fopen("digit.in","rb");
    fout=fopen("digit.out","wb");

    int n,cnt=1;
    fscanf(fin,"%d",&n);
    while(n/10)
    {
        cnt++;
        n/=10;
    }
    fprintf(fout,"位数:%d\n",cnt);
    fclose(fin);
    fclose(fout);
    return 0;
}

习题2-2 水仙花数(daffodil)

问题描述:输出100~999中所有的水仙花数。若三位数ABC满足ABC=A^3+B^3+C^3;则称其为水仙花数,例如153=1^3+5^3+3^3,所以153是水仙花数。

重定向版:

#define LOCAL
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
    #ifdef LOCAL
        freopen("daffodil.in","r",stdin);
        freopen("daffodil.out","w",stdout);
    #endif // LOCAL
    int a=0,b=0,c=0;
    for(int i=100;i<=999;i++)
    {
        a=i%10;
        b=i/10%10;
        c=i/100;
        if(i==(pow(a,3)+pow(b,3)+pow(c,3)))
        {
            printf("%d ",i);
        }
    }
    printf("\n");
}

fopen版:
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
    FILE *fout;
    fout=fopen("daffodil.out","wb");

    int a=0,b=0,c=0;
    for(int i=100;i<=999;i++)
    {
        a=i%10;
        b=i/10%10;
        c=i/100;
        if(i==(pow(a,3)+pow(b,3)+pow(c,3)))
        {
            fprintf(fout,"%d ",i);
        }
    }
    fprintf(fout,"\r\n");
    fclose(fout);
}


习题2-3 韩信点兵(hanxin)

问题描述:相传韩信才智过人,从不直接清点自己军队的人数,只要让士兵先后以三人一排、五人一排、七人一排德变换队形,而他每次只掠一眼队伍的排尾就知道总人数了。输入三个非负整数a,b,c,表示每种队形排尾的人数(a<3,b<5,c<7),输出总人数的最小值(或报告无解)。已知总人数不小于10,不超过100。

重定向版:

#define LOCAL
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int a,b,c;
int main()
{
    #ifdef LOCAL
      freopen("hanxin.in","r",stdin);
      freopen("hanxin.out","w",stdout);
    #endif // LOCAL
    while(scanf("%d%d%d",&a,&b,&c)==3)
    {
        bool flag=false;
        int num;
        for(int i=10;i<=100;i++)
        {
            if(i%3==a&&i%5==b&&i%7==c)
            {
                flag=true;
                num=i;
                break;
            }
        }
        if(flag==true)
        {
            printf("%d\n",num);
        }
        else
        {
            printf("No answer\n");
        }
    }
}

fopen版:

#include<iostream>
#include<fstream>
#include<stdio.h>
using namespace std;
int main()
{
    FILE *fin,*fout;
    fin=fopen("hanxin.in","rb");
    fout=fopen("hanxin.out","wb");
    int a,b,c;
    while(fscanf(fin,"%d%d%d",&a,&b,&c)==3)
    {
        bool flag=false;
        int num;
        for(int i=10;i<=100;i++)
        {
            if(i%3==a&&i%5==b&&i%7==c)
            {
                flag=true;
                num=i;
                break;
            }
        }
        if(flag==true)
        {
            fprintf(fout,"%d\r\n",num);
        }
        else
        {
            fprintf(fout,"No answer\r\n");
        }
    }
    fclose(fin);
    fclose(fout);
    return 0;
}

习题2-4 倒三角形(triangle)

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

#########

  #######

    #####

     ###

       #

重定向版:

#define LOCAL
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
int main()
{
    #ifdef LOCAL
       freopen("triangle.in","r",stdin);
       freopen("triangle.out","w",stdout);
    #endif // LOCAL
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<i;j++)
        {
            printf(" ");
        }
        for(int j=1;j<=(n-i+1)*2-1;j++)
        {
            printf("#");
        }
        printf("\n");
    }
}

fopen版:

#include<iostream>
#include<stdlib.h>
#include<fstream>
#include<stdio.h>
using namespace std;
int main()
{
    FILE *fin,*fout;
    fin=fopen("triangle.in","rb");
    fout=fopen("triangle.out","wb");
    int n;
    fscanf(fin,"%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<i;j++)
        {
            fprintf(fout," ");
        }
        for(int j=1;j<=(n-i+1)*2-1;j++)
        {
            fprintf(fout,"#");
        }
        fprintf(fout,"\r\n");
    }
}


习题2-5 统计(stat)

问题描述:输入一个正整数n,然后读取n个正整数a1,a2,a3.......an,最后再读取一个正整数m。统计a1,a2,a3........an中有多少个整数的值小于m。

提示:如果重定向和fopen都可以使用,那个比较方便。

选择fopen,因为fopen可以反复打开并读写文件。

fopen版:

#include<stdio.h>
#include<stdlib.h>
#include<fstream>
int main()
{
    FILE *fin,*fout;
    fin=fopen("stat.in","rb");
    fout=fopen("stat.out","wb");

    int n,a[10000];
    fscanf(fin,"%d",&n);
    for(int i=0;i<n;i++)
    {
        fscanf(fin,"%d",&a[i]);
    }
    int m;
    fscanf(fin,"%d",&m);
    int cnt=0;
    for(int i=0;i<n;i++)
    {
        if(a[i]<m)
        {
            cnt++;
        }
    }
    fprintf(fout,"%d\r\n",cnt);
    fclose(fin);
    fclose(fout);
}

习题2-6 调和级数(harmony)

问题描述:输入正整数n,输出H(n)=1+1/2+1/3+......+1/n的值,保留三位小数。例如n=3时,答案为1.7=833。

重定向方法:

#define LOCAL
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
int main()
{
    #ifdef LOCAL
       freopen("harmony.in","r",stdin);
       freopen("harmony.out","w",stdout);
    #endif // LOCAL
    int n;
    scanf("%d",&n);
    double res=0;
    for(int i=1;i<=n;i++)
    {
        res+=1.0/i;
    }
    printf("%.3lf\n",res);
    return 0;

}

习题2-7 近似计算(approximation)

问题描述:计算PI/4=1-1/3+1/5-1/7+......,直到最后一项小于10^(-6)。

重定向方法:

#define LOCAL
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
    #ifdef LOCAL
       freopen("approximation.in","r",stdin);
       freopen("aproximation.out","w",stdout);
    #endif // LOCAL
    int i=1,sign=-1;
    double res=1;
    do
    {
        res+=1.0/(2*i+1)*sign;
        i++;
        sign=-sign;
    }while(fabs(1.0/(2*i+1))>=10e-6);
    printf("%lf\n",4*res);
    return 0;

}

习题2-8 子序列的和(subsequence)

问题描述:输入两个整数n<m<10^6,输出1/(n^2)+1/((n+1)^2)+.....+1/(m^2),保留5位小数。例如n=2,m=4时答案是0.42362;n=65536,m=655360时答案是0.00001。

注意:本题有陷阱。

重定向方法:

#define LOCAL
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
    #ifdef LOCAL
       freopen("subsequence.in","r",stdin);
       freopen("subsequence.out","w",stdout);
    #endif // LOCAL
    int n,m,i;
    double res=0;
    scanf("%d%d",&n,&m);
    for(int i=n;i<=m;i++)
        res+=1.0/((long long)i*i;
    printf("%.5lf\n",res);
    return 0;
}


习题2-9 分数化小数(decimal)

问题描述:输入整数a,b,c,输出a/b的小数形式,精确到小数点后c位。a,b<=10^6,c<=100。例如:a=1,b=6,c=4时应输出0.1667。

重定向方法:

#define LOCAL
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
    #ifdef LOCAL
       freopen("decimal.in","r",stdin);
       freopen("decimal.out","w",stdout);
    #endif // LOCAL
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    cout.setf(ios::fixed);
    cout.setf(ios::showpoint);
    cout.precision(c);
    cout<<(double)a/(double)b;
    return 0;
}

习题2-10 排列(permutation)

问题描述:用1,2,3...,9组成3个三位数abc,def和ghi,每个数字恰好使用一次,要求abc:def:ghi=1:2:3,输出所有解。提示:不必太动脑筋。

重定向方法:

#define LOCAL
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<cmath>
using namespace std;
//用1,2,3……,9组成3个三位数abc,def和ghi,每个数字恰好使用一次,要求abc:def:ghi=1:2:3.输出所有解。

#include <stdio.h>

void result(int num, int &result_add, int &result_mul)
{
    int i, j, k;

    i = num / 100;        //百位
    j = num / 10 % 10;    //十位
    k = num % 10;         //个位

    result_add += i + j + k;    //分解出来的位数相加
    result_mul *= i * j * k;    //相乘
}

int main()
{
    #ifdef LOCAL
    // freopen("permutation.in","r",stdin);
       freopen("permutation.out","w",stdout);
    #endif // LOCAL
    int i, j, k;
    int result_add, result_mul;
    for(i = 123; i <=329; i++)
    {
        j = i * 2;
        k = i * 3;
        result_add = 0;
        result_mul = 1;
        result(i, result_add, result_mul);
        result(j, result_add, result_mul);
        result(k, result_add, result_mul);

        if(result_add == 45 && result_mul == 362880)
            printf("%d %d %d\n", i, j, k);
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!