【算法竞赛入门经典】【第二章】课后习题

      《 算法竞赛入门经典》课后题解,第二发来袭。

习题2-1 位数(digit)

#include <stdio.h>

int main()
{
    int n,digit;
    while(~scanf("%d",&n)){
        digit = 0;
        if(n==0)
            digit = 1;
        while(n>0){
            n /= 10;
            digit++;
        }
        printf("%d\n",digit);
    }
    return 0;
}

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

       这是一个很经典的问题,对于本题数据量比较小,所以我们直接使用暴力求解

#include <stdio.h>

int main()
{
    int p1,p2,p3,i;
    for( i = 100; i < 1000; i++){
        p1 = i/100;
        p2 = (i - 100*p1)/10;
        p3 = i%10;
        if( i == p1*p1*p1 + p2*p2*p2 + p3*p3*p3 )
            printf("%d ",i);
    }
    return 0;
}

习题2-3 韩信点兵(hanxin)背景故事

       果断暴力求解:

#include <stdio.h>

int main()
{
    int i,a,b,c;      //a,b,c分别是3人一排,5人一排,7人一排的剩余人数
    while(~scanf("%d%d%d",&a,&b,&c)){
        for(i = 10; i <= 100; i++){     //暴力求解
            if(i%3==a&&i%5==b&&i%7==c){
                printf("%d\n",i);
                break;
            }
        }
        if(i>100)
            printf("No answer\n");
    }
    return 0;
}


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

        这一题属于字符串处理的题目,本题需要特别注意的地方就是倒三角右侧的空白与左侧空白的区别,这个弄明白这类的题目通常都差不多

#include <stdio.h>

int main()
{
    int n,p1,p2,i,j,k;      //其中p1代表#的个数,p2代表空格的个数
    while(~scanf("%d",&n)){
        p1 = 2*n -1;
        p2 = 0;
        for( i = 0; i < n; i++){
            for( j = 0; j < p2; j++)
                printf(" ");
            for( k = 0; k < p1; k++)
                printf("#");
            printf("\n");
            p2++;
            p1-=2;
        }
    }
    return 0;
}

习题2-5 统计(stat)

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int n,m,i,cnt;    //cnt为计数器,用于记录大于m的数的个数
    while(scanf("%d",&n)){
        int *a = (int*)malloc(sizeof(int)*n);   //动态申请内存
        cnt = 0;        //计数器初始化
        for( i = 0; i < n; i++ )
            scanf("%d",&a[i]);
        scanf("%d",&m);
        for( i = 0; i < n; i++ ){
            if( a[i] < m )
                cnt++;
        }
        printf("%d\n",cnt);
        free(a);
        a = NULL;
    }
    return 0;
}

重定向版:

#define LOCAL
#include <stdio.h>
#include <stdlib.h>
int main()
{
#ifdef LOCAL
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
#endif
//后面一样
}

fopen版:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE* fin,*fout;
    fin = fopen("data.in","rb");
    fout = fopen("data.out","wb");
    int n,m,i,cnt;    //cnt为计数器,用于记录大于m的数的个数
    while(fscanf(fin,"%d",&n)==1){
        int *a = (int*)malloc(sizeof(int)*n);   //动态申请内存
        cnt = 0;        //计数器初始化
        for( i = 0; i < n; i++ )
            fscanf(fin,"%d",&a[i]);
        fscanf(fin,"%d",&m);
        for( i = 0; i < n; i++ ){
            if( a[i] < m )
                cnt++;
        }
        fprintf(fout,"%d\n",cnt);
        free(a);
        a = NULL;
    }
    fclose(fin);
    fclose(fout);
    return 0;
}

就方便而言个人认为重定向的方法比较简便

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

#include <stdio.h>

double Slove(int n)
{
    int i;
    double f = 0;
    for( i = 1; i <= n; i++ )
        f += 1.0/i;
    return f;
}

int main()
{
    int n;
    while(scanf("%d",&n))
        printf("%.3lf\n",Slove(n));
    return 0;
}

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

#include <stdio.h>

int main()
{
    int i,p = 1;
    double sum,temp_i;
    for( i = 1;;i++){
        temp_i = 1.0/i;
        sum += p*temp_i;
        p = -p;
        if(temp_i < 10e-6)
            break;
    }
    printf("%lf\n",4*sum);
    return 0;
}

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

       本题的陷阱是当n过大时,会造成 n*n溢出

#include <stdio.h>

int main()
{
    int n,m,i;
    double sum;
    while(scanf("%d%d",&n,&m)){
        sum = 0;
        for( i = n; i <= m; i++ )
            sum += 1.0/i*1.0/i;
        printf("%.5lf\n",sum);
    }
    return 0;
}

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

       这一题,使用借位的方法就可顺利解决,同时需要采用模拟数组的方法

#include <stdio.h>
#include <stdlib.h>

int digit(int n){
    int cnt = 0;
    while(n>0){
        n/=10;
        cnt++;
    }
    return cnt;
}
int main()
{
    int a,b,c,n,dgt,temp,i,k;	//a,b,c如题意所示,n表示a/b的整数部分,dgt表示n的位数
    char *p;
    while(scanf("%d%d%d",&a,&b,&c)){
		i = 0;
        n = a/b;
        if( n < 1){
			dgt = 1;
            p = (char*)malloc(sizeof(char)*(c+10));
            p[i++] = '0';
            p[i++] = '.';
        }
        else{
            dgt = digit(n);
	    a = a - n*b;
            p = (char*)malloc(sizeof(char)*(dgt+c+10));
            i = dgt,k = dgt;
            while(k>0){
                p[--k] ='0' + n%10;
                n /= 10;
            }
            p[i++] = '.';
        }
        while(i<=c+dgt+1){
            a *= 10;
            temp = a / b;
            a %= b;
            p[i++] = temp + '0';
        }
		if(p[i-1]>='5')
			p[i-2] = p[i-3] + 1;
        p[i-1] = '\0';
        puts(p);
        free(p);
        p =NULL;
    }
    return 0;
}

习题2-10 排列(permutation)

#include <stdio.h>

int main(){
    int a,b,c,num[10]={0},i,tmp;
    for(a = 100; a < 333; a++ ){  //因为 c <1000 => a <333
        b = 2 * a, c = 3 * a;
        //将使用过的数字进行标记
        num[a/100] = num[a/10%10] = num[a%10] = 1;
        num[b/100] = num[b/10%10] = num[b%10] = 1;
        num[c/100] = num[c/10%10] = num[c%10] = 1;
        i = 1,tmp = 0;
        while(i<10)
            tmp += num[i++];
        if( tmp == 9 )  //将使用过的数字进行统计
            printf("%d %d %d\n",a,b,c);
        for(i = 1; i < 10; i++) //将数字的标记擦除
            num[i] = 0;
    }
    return 0;
}

【第一章】课后习题详解: 传送门
【第三章】课后习题详解: 传送门

你可能感兴趣的:(【算法竞赛入门经典】【第二章】课后习题)