算法竞赛入门经典(第二版) 刘汝佳编著 第二单元习题

习题2-1 水仙花数

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

     此题比较简单,通过蛮力法,然后分离每个数的个、十、百位,然后进行判断即可。

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
    int i,a,b,c;
    for( i = 100; i <= 999; i++)
    {
         a = i/100;//分离出百位
         c = i%10;//分离出个位
         b = (i/10)%10;//分离出十位
        if(i == a*a*a+b*b*b+c*c*c)//判断是否为水仙花数
            printf("%d\n",i);
    }
    return 0;
}

 

习题2-2 韩信点兵

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

样例输入:

2 1 6

2 1 3

样例输出:

Case 1: 41

Case 2:No answer

可能一开始看题目有点懵,先后以三人一排,五人一排,七人一排变换队形是指将军队的所有的人先按三人一排排队,记下余数,然后按五人一排排队,记下余数,之后同理。因为题目所给的数据不大,蛮力法就可以解决。

 

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
    int a,b,c,i;
    int num = 1;
    while(scanf("%d%d%d",&a,&b,&c) != EOF)
    {
        for(i = 10; i <= 100; i++)
        {
            if(i%3 == a && i%5 == b&& i%7 == c)//如果这个数满足条件,则跳出循环,确保是最小的数。
            break;
        }
        if(i > 100)
            printf("Case %d: No answer\n",num);
        else
            printf("Case %d: %d\n",num,i);
            num++;
    }

    return 0;
}

习题2-3 倒三角形

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

#########

 #######

  #####

   ###

    #

这一题比较简单,大概注意两点就好。每一层#的个数和空格的个数。当n=5时,第一行有2*5-1个"#",第二行有2*4-1个“#”,其他行同样的规律。第一行没有空格,第二行有一个空格,其他行也是同样的规律。代码如下

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
    int n,i;
    while(scanf("%d",&n) != EOF)
    {
        if(n > 20)
            break;
            int t = 0;//t用来记录每一行的空格的规律
        for(i = n; i > 0; i--)
        {
            for(int m = 0; m < t; m++)
                printf(" ");//打印每一行的空格
            for(int j = 0; j < 2*i-1; j++)
            {
                printf("#");//打印每一行的#号
            }
            printf("\n");
            t++;
        }

    }
    return 0;
}

 

习题2-4  子序列的和

   输出两个正整数n<m<10^6,输出1/(n*n)+1/((n+1)*(n+1))+...+1/m*m,保留五位小数,输入包含多组数据,结束标记为n=m=0.提示本题有陷阱。

样例输入:

2 4

65536 655360

0 0

样例输出:

Case 1: 0.42361

Case 2: 0.00001

 

此题有什么陷阱呢?从样例的第二个输入就可以看出来,如果用int来表示是会溢出的,所以这里我们用long long 类型就好了。

​
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
    long long a,b;
    int num = 0;
    while(scanf("%lld%lld",&a,&b) != EOF)
    {
        if(a == 0|| b == 0)
            break;
            double sum = 0;
        for(long long i = a; i <= b; i++)
        {
            sum += 1.0/(i*i);
        }
        printf("Case %d: %.5f\n",++num,sum);
    }
    return 0;
}

​

 

习题2-5 分数化小数

输入正整数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 <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
    long long a,b,c;
    int num = 0;
    while(scanf("%lld%lld%lld",&a,&b,&c) != EOF)
    {
        if(a == 0&& b == 0&& c == 0) break;
        printf("Case %d: %lld.",++num,a/b);//先打印出整数部分和小数点
        a = a%b;
        for(int i = 1;i < c; i++)//模拟除法得到c-1位小数
        {
            a = a*10;
            printf("%lld",a/b);
            a = a%b;
        }
        int m = a*10/b;//得到第c位小数
        a = a*10%b;
        int n = a*10/b;//得到第c+1位小数
        if(n >= 5)//进行四舍五入
            printf("%d\n",m+1);
        else
            printf("%d\n",m);
    }
    return 0;
}

 

习题2-6  排列

用1,2,3,...,9组成三个三位数abc,def和ghi,每个数字恰好使用一次,要求abc:def:ghi=1:2:3。按照“abc def ghi”的格式输入所有解,每行一个解。

主要还是得通过蛮力法来做,但我们可以通过计算来减小循环的次数。

1-9构成的最小的数字排列应该是123(百位取1的时候最小,当1被用过之后,十位取2最小,当1,2都被用过之后,个位取三最小),同理1-9构成的最大数字排列应该是987,我们假设构成的最小排列数是i,又因为三个排列之比为1:2:3,所以最大的数应该为3*i,这是循环的控制条件就可以出来了:3*i<=987.

唉,同时我们还要思考另外一个问题,我们该怎么来保证1-9中的数字使用有且仅有一次,这个时候我们选择使用一个辅助数组a[10],一开始给这个数组的每个元素都赋值为0,a[1]对于1这个数字,a[2]对于2这个数字,以此类推,如果这个数字被用过了,则这个数字对应的数组元素就赋值为1.如果在循环结束后,数组中a[1]-a[9]的元素之和等于9(只有当每个数字都使用了一次,和才会为9,否则都是小于9的),这时我们就可以判定1-9中的元素使用了有且仅以一次。

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
    int i,j,m,n;
    int a[10];
    for(i = 123; i*3 <= 987; i++)
    {
        int sum = 0;
        for(j = 0; j < 10; j++)
        {
            a[j] = 0;
        }//每进行一次循环前都要将辅助数组赋值为0
        a[i/100] = 1;
        a[(i/10)%10] = 1;
        a[i%10] = 1;
        m = i*2;
        a[m/100] = 1;
        a[(m/10)%10] = 1;
        a[m%10] = 1;
        n = i*3;
        a[n/100] = 1;
        a[(n/10)%10] = 1;
        a[n%10] = 1;
        for(j = 1; j < 10; j++)
            sum += a[j];
            if(sum == 9)
                printf("%d %d %d\n",i,m,n);
    }
    return 0;

}

想提高自己的算法能力,所以现在开始认真的刷紫书,欢迎大家指出我的错误或者提出更好的问题解决办法

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值