《算法竞赛入门经典》上机练习——第二章

习题2-1 位数(digit)

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

#include <stdio.h>

int main()
{
    int x,num=0;
    scanf("%d",&x);
    while(x)
    {
    	x/=10;
    	num++;
    }
    printf("%d\n",num);
	
	return 0;
} 



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

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

#include <stdio.h>

int main()
{
    int i,a,b,c;
    for(i=100; i<=999; i++)
    {
    	a = i%10;     /*个位*/
    	b = i/10%10;  /*十位*/
    	c = i/100;    /*百位*/
    	if(i == a*a*a + b*b*b + c*c*c)
    	    printf("%d\n",i);
    }
	
	return 0;
} 
结果:三位水仙花数有:153,370,371,407



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

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

    样例输入:2 1 6

    样例输出:41

    样例输入:2 1 3

    样例输出:No answer

#include <stdio.h>

int main()
{
    int i,a,b,c;
    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 == 101)
        printf("No answer\n");
	
	return 0;
} 


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

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

#########
 #######
  #####
   ###
    #

#include <stdio.h>

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


习题2-5 统计(stat)

    输入一个正整数n,然后读取n个正整数a1,a2,...,an,最后再读一个正整数m。统计a1,a2,...,an中有多少个数小于m。提示:如果重定向和fopen都可以使用,哪个比较方便?


这道不会。。。欢迎指教!



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

    输入正整数 n,输出 H(n) = 1 + 1/2 + 1/3 +...+ 1/n 的值,保留3位小数。例如n=3时答案为1.833。

#include <stdio.h>

int main()
{
    int n,i;
    double H = 0;
    scanf("%d",&n);
    for(i=1; i<=n; i++)
    	H += 1.0/i;
    printf("%.3lf\n",H);
	
	return 0;
} 


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

    计算pi/4 = 1 - 1/3 + 1/5 - 1/7 + ...,直到最后一项小于10^(-6)。

#include <stdio.h>

int main()
{
    int i=1,flag=1;
    double sum=0,item=1.0;
    
    while(item>=1.0/1000000)
	{
		sum += flag*item;
		flag *= -1;
		i += 2;
		item = 1.0/i;
    }
    
    printf("pi = %lf\n",sum*4); 
	
	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.42361;n=65536,m=655360 时答案为0.00001,。注意:本题有陷阱。

#include <stdio.h>

int main()
{
    int i,n,m;
    double sum=0;
    scanf("%d%d",&n,&m);
    
    for(i=n;i<=m;i++)
    	sum += 1.0/i/i;
    
    printf("%.5lf\n",sum); 
	
	return 0;
} 
本题陷阱:当n或m比较大时,i * i 会溢出,不能用 1.0 / ( i * i ) ,应该用 1.0 / i / i 。 或者改用long long数据类型。



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

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

#include <stdio.h>

int main()
{
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    printf("%.*lf\n",c,1.0*a/b); /*新知识:格式控制符中,* 可由后边的变量替代!*/
	
	return 0;
} 

此种方法的问题是,当c较大时,超过十几位小数后边的小数部分都只显示零,不知道为什么。

以下是逐位计算小数的方法,就完全没问题了。(此段代码非我所写,注释是我加的,代码出处见博客尾。)

#include <stdio.h>
 
int main(void) 
{ 
    int a,b,c,mod,re,i,m,x,y;
    while(scanf("%d%d%d",&a,&b,&c)==3)
    {
        printf("%d",a/b);   /*输出整数部分*/ 
        mod=a%b;
        if(c>0)
        {
            printf(".");
            for(i=1;i<c;i++)  /*逐位计算输出c-1位小数*/
            {
                m=mod*10;
                re=m/b;
                printf("%d",re);
                mod=m%b;
            }
            m=mod*10;
            x=m/b;
            mod=m%b;    /*往后多算一位,四舍五入到我们所需的最后一位*/
            m=mod*10;
            y=m/b;
            if(y>=5)
            x++;
            printf("%d\n",x);  /*输出最后一位小数*/ 
        }
    }
    return 0; 
}


习题2-10 排列(permutation)

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

#include<stdio.h>

int arr[10] = {0};/*数组arr用来记录1~9每个数字是否出现,与下标一一对应,出现为1,否则为0*/

int main()
{
	int a,b,c,d,e,f,g,h,i,abc,def,ghi,t,sum;
	for(a=1;a<=3;a++)  /*a最大为3*/ 
	  for(b=1;b<=9;b++)
	    for(c=1;c<=9;c++)
		  for(d=2;d<=6;d++)  /*d最小为2,最大为6*/ 
		    for(e=1;e<=9;e++)
			  for(f=1;f<=9;f++)
			    for(g=3;g<=9;g++)  /*g最小为3*/ 
			      for(h=1;h<=9;h++)
			        for(i=1;i<=9;i++)
	                {
	                    for(t=1;t<=9;t++)
						    arr[t] = 0;
										    
						arr[a] = 1;arr[b] = 1;arr[c] = 1;
						arr[d] = 1;arr[e] = 1;arr[f] = 1;
					    arr[g] = 1;arr[h] = 1;arr[i] = 1;
										
						sum = 0;
	                    for(t=1;t<=9;t++)  /*若数组累加和为9,表示1~9的数字全部出现*/ 
                            sum+=arr[t];
	                    if(sum==9)
                        {
	                     	abc = a*100+b*10+c;
	                        def = d*100+e*10+f;
	                        ghi = g*100+h*10+i;
			                if(abc*2==def && abc*3==ghi)
			                    printf("%d:%d:%d = 1:2:3\n",abc,def,ghi);
	                    }
	                }
	
	return 0;
}

结果:

192:384:576 = 1:2:3

219:438:657 = 1:2:3

273:546:819 = 1:2:3

327:654:981 = 1:2:3


还有网上的另一种方法,一定程度的逆向思维,精妙,运行速度比我的多层for循环嵌套快多了,我的程序循环次数有3*9*9*5*9*9*7*9*9 = 55801305次,而以下程序只有333-100 = 233次。

#include <stdio.h>

int main(void)
{
	int x, y, z, a[10] = {0};
	for(x = 100; x < 333; x++)
	{
		y = 2*x;
		z = 3*x;
		//令a[出现的数字] = 1
		a[x/100] = a[x/10%10] = a[x%10] = 1;
		a[y/100] = a[y/10%10] = a[y%10] = 1;
		a[z/100] = a[z/10%10] = a[z%10] = 1;
		int i, s = 0;
		for(i = 1; i < 10; i++)
			s += a[i];
		if(s == 9)
			printf("%d\t%d\t%d\n", x, y, z);
		for(i = 1; i < 10; i++)	//重新赋值为0
			a[i] = 0;
	}
	return 0;
}



若有错误遗漏欢迎指出,欢迎交流讨论。

注:本文部分参考此篇博客:http://blog.csdn.net/litiouslove/article/details/7891700

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值