习题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;
}
想提高自己的算法能力,所以现在开始认真的刷紫书,欢迎大家指出我的错误或者提出更好的问题解决办法