算法竞赛入门经典(第2版)习题

2.5 注解与习题

2-1 水仙花数(daffodi)

输出100~999中所有水仙花数。若三位数ABC满足 A B C = A 3 + B 3 + C 3 ABC=A^3+B^3+C^3 ABC=A3+B3+C3,则称其为水仙花数。例如 153 = 1 3 + 5 3 + 3 3 。 153=1^3+5^3+3^3。 153=13+53+33

//输出100~999中所有水仙花数
#include<stdio.h>

int main(){
	int a,b,c;
	for(int i=100;i<1000;i++){
		a = i/100;
		b = (i - a*100)/10;//i/10 - a*10;
		c = i%10;
		if(a*100+b*10+c == a*a*a+b*b*b+c*c*c){
			//printf("i = %d\n",i);
			printf("%d ",a*a*a+b*b*b+c*c*c);
		}
			
	}
	
	// for(a=1;a<10;a++){
		// for(b=0;b<10;b++){
			// for(c=0;c<10;c++){
				// if(a*100+b*10+c == a*a*a+b*b*b+c*c*c){
					// printf("%d ",a*100+b*10+c);
				// }
			// }
		// }
	// }
	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

//韩信点兵
#include<stdio.h>
typedef enum{false,true}bool;
int main(){

	int a,b,c;
	bool find_answer; 		//标志位
	int count = 0;			//计数器,每输入一组数,count加1

	while(scanf("%d%d%d",&a,&b,&c) == 3){
		find_answer = false;
		printf("Case %d:",count++);
		for(int i=10;i<=100;i++){
			if((i-a)%3==0 && (i-b)%5==0 && (i-c)%7==0){
				find_answer = true;
				printf("%d\n",i);
			}
		}
		if(!find_answer){
			printf("No answer\n");
		}
			
	}
	
	return 0;
}

2-3倒三角(triangle)

输入正整数n<=20,输出一个n层的倒三角型。
“当输入n=5时”
输出

*********
 *******
  *****
   ***
    *

代码

//triangle
//Input:n
//Output:n层倒三角
#include<stdio.h>

int main(){
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		for(int j=0;j<n*2-1 - i;j++){
			if(j<i)
				printf(" ");
			else
				printf("*");
		}
		printf("\n");
		
	}
}

思路:

  1. 倒三角从下到上按照1, 3, 5,7… n × 2 + 1 n\times2+1 n×2+1递增
  2. 打印一个长方形
for(int i=0;i<n;i++){
		for(int j=0;j<n*2-1 ;j++){
			printf("*");
		}
*********
*********
*********
*********
*********
  1. 每层打印的*数量减1,去掉右下的三角形
for(int i=0;i<n;i++){
		for(int j=0;j<n*2-1 - i;j++){
			printf(" ");
		}
*********
********
*******
******
*****
  1. 第i层,前i个*替换成空格,去掉左下的三角形
for(int i=0;i<n;i++){
		for(int j=0;j<n*2-1 - i;j++){
			if(j<i)
				printf(" ");
			else
				printf("*");
		}
*********
 *******
  *****
   ***
    *

2021.3.11


2-4子序列的和(subsequence)

输入两个·正整数 n < m < 1 0 6 n<m<10^6 n<m<106 输出 1 n 2 + 1 n 2 + 1 + . . . + 1 m 2 \frac{1}{ n^2}+\frac{1}{ n^2+1}+...+\frac{1}{ m^2} n21+n2+11+...+m21
保留5位小数。输入包含多组数据,结束标记为n=m=0。提示:本题有陷阱
样例输入

2 4
65536 655360
0 0

样例输出

Case 10.42361
Case 20.00001

代码

//子序列的和(subsequence)
#include<stdio.h>

int main(){
	int a,b;
	long double s;
	int count = 1;
	while(scanf("%d%d",&a,&b)==2){
		s = 0;
		if(a==0 && b==0) break;
		else if(a<b){
			for(int i=a;i<=b;i++){
				//printf("s=%Lf\t",s);
				//printf("i=%d\t",i);
				//s += 1.0/(i*i*1.0);
				s += (1.0/i)*(1.0/i);
			}
			//printf("\n");
			printf("Case %d:%.5Lf\n",count++,s);
		}else{
			return 1;
		}
	}
	return 0;
}

65536655360的值超出了int的范围*

65536*655360 = 42949672960
2**32        = 4294967296
2**64        = 18446744073709551616

2-5 分数化小数

输入正整数a, b, c, 输出a/b的小数形式,精确到小数点后c位。 a , b ≤ 1 0 6 , c ≤ 100 。 a,b\le10^6,c\le100。 a,b106,c100
数入包含多组数据,结束标记为a=b=c=0。

样例数入:

1 6 4
0 0 0

样例输出:

Case 10.1667

代码

// 2-5 分数化小数(decimal)
#include<stdio.h>

int main(){
	int a,b,c;
	int count = 1;
	// 输入正整数a, b, c
	while(scanf("%d%d%d",&a,&b,&c)==3){
		if(a==0 && b==0 && c==0) break; // 结束标记为a=b=c=0
		else if(a>0 && b>0 && c>0){
			printf("Case %d:%.*f\n",count++,c,a*1.0/b);
		}else return 1;
	}
	return 0;
}

2-6 排列(permutation)

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

// 2-6 排列(permutation)
#include<stdio.h>

int main(){
	int a,b,c;
	int array[9];
	int temp;
	int count;
	int flag_right = 0; // 标志位
	
	for(a=1;a<10;a++){
		for(b=1;b<10;b++){
			if(a==b) continue;
			for(c=1;c<10;c++){
				count = 0; // 记录有无重复数字
				
				if(c==b || c== a) continue;
				temp = a*100+b*10+c;
				if(temp*3>999) continue;
				array[0] = a;
				array[1] = b;
				array[2] = c;
				
				array[3] = (temp*2)/100;
				array[4] = (temp*2)/10 - array[3]*10;
				array[5] = (temp*2)%10;
				
				array[6] = (temp*3)/100;
				array[7] = (temp*3)/10 - array[6]*10;
				array[8] = (temp*3)%10;
				
				for(int i=0;i<9;i++){
					for(int j=i;j<9;j++){
						if(i==j) continue;
						
						if(array[j] == array[i] || array[j]==0){ //出现重复数字或者0则退出
							count++;
							break;
						}
					}
					if(count>0) break; // 有数字重复
				}
				if(count == 0) printf("%d %d %d\n",temp,temp*2,temp*3);
				
			}
		}
	}
	return 0;
}

运行结果

192 384 576
219 438 657
273 546 819
327 654 981

思路
很自然的想法是对temp = abc 做乘法得到其余数字,用数组将这些数字保存然后遍历查看无重复数字,记得数字中不能有0。

思考题

题目1

假设需要输出2,4,6,8,…,2n, 每个一行,能不能通过对程序2-1进行小小的改动来实现呢?为了方便,现在把程序复制如下:

#include<stdio.h>
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		printf("%d\n",i);
	return 0;
}

任务1:修改第7行,不修改第6行
任务2:修改第6行,不修改第7行

代码

#include<stdio.h>
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=2;i<=n*2;i*=2)   // 任务2
		printf("%d\n",i/*2*/); // 任务1: i -> i*2
	return 0;
}

题目2

下面的程序运行结果是什么? “!=” 算法运算符表示不相等。提示:请上机实验,不要凭主观感觉回答。

#include<stdio.h>
int main()
{
	double i;
	for(i=0;i!=10;i+=0.1)
		printf("%.1f\n",i);
	return 0;
}

直觉上好像会打印0.0, 0.1, …, 9.9,但实际上会无限打印下去,因为double是浮点数,它无法精确地等于整型10。

4489.4
4489.5
4489.6
4489.7
4489.8
4489.9
4490.0
4490.1
4490.2
4490.3
4490.4
4490.5
4490.6

测试
将修改代码为:

#include<stdio.h>
int main()
{
	double i;
	for(i=0;i!=10;i+=0.1){
		if ((int)i>=10){
			printf("(int)i = %d",(int)i);
			break;
		}
		
		printf("%.1f\n",i);	
	}
		
	return 0;
}

可以看到打印结果:

9.4
9.5
9.6
9.7
9.8
9.9
10.0
(int)i = 10

当i等于10.0时,不等式(int)i==10并不成立,我们知道用(int)强制类型转换会丢弃掉所有小数部分,由此可知当i的打印只是10.0的时候,它的实际值是小于10的,比如9.9999999。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值