刘汝佳算法竞赛入门例题-循环部分

发布于:2022-12-18 ⋅ 阅读:(288) ⋅ 点赞:(0)

        今天是学习acm的第一天,记录一些学习的心得。

p34-韩信点兵

        简要题干:输入a、b、c,表示军队人数模3,模5,模7的余数

                          输出 军队总人数

                           总人数不小于10,不超过100。

               做每一道题之前,我们首先要做的就是判断数据大小,本题中最大输入数据3,5,7小于int的范围,运算最大数据是100,没有超出了int的范围

                明白了这点后,其次就是递归寻找总人数,一般的递归会长这个样子。


#include<cstdio>
using namespace std;
int main(){
	int a,b,c,sum,n=0;
	while(scanf("%d%d%d",&a,&b,&c)){//分别输入模三,模五,模七的余数
		int i;
		for(i=10;i<=100;i++){			//人数限制
			if(i%3 ==a && i%5 ==b && i%7==c){//判断人数是否符合条件
				printf("Case %d: %d",++n,i);
				break;//得到数字后跳出循环判断
			}
			
		}
		if(i>100){//在10-100中没有对应的数字,跳出后输出
			printf("Case %d: No Answer",++n);
		}
	}
	return 0;
}

但是我们仔细观察,发现他循环了90次,执行时间太长了,我们可不可以进行优化呢,答案是可以的。

样例如下,我们来观察一下有什么区别。

#include <iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;

int main()

{

     int a,b,c,n=0;
     while(scanf("%d %d %d",&a,&b,&c)!=0)
     {
         int i://循环因子
         if(7+c>10)
         {
             i=7+c;
             
         }
         else
            i=14+c;
         for(i;i<=100;i+=7)//i=1+7 和 i+=7 一样,但是 i+=7 更快
         {
             
             if(i%5==b&&i%3==a)
             {
                 
                 printf("Case %d: %d",++n,i);
				break;//得到数字后跳出循环判断
             }
             
         }
         if(i>100)
         {
             
             printf("Case %d: No Answer",++n);
         }

     }
 return 0;

}

   

确实下面的这种检索方式要比上面快很多,这就是acm的目的,谁程序可以优化的最好,我们平时在练习中就要意识到这一点。

p35-子序列的和

        简要题干:给定两个数:m、n(数据范围n<m<10的6次方),要求输出从1/n^2+1/(n+1)^2....+1/m^2的值的前五位小数。

输入包含多组数据。结束标记为n=m=0。

        做每一道题之前,我们首先要做的就是判断数据大小,本题中最大输入数据10的6次方小于int的范围,但是运算最大数据10的12次方,超出了int的范围所以需要优化,有些人可能会选择使用long,但是这里我们将1/n^2变为1/n/n,这个数据越界的问题就解决了。

        我们开始分析这道题,“输入包含多组数据。结束标记为n=m=0”这有通用的代码,即为

while(scanf("%d%d",&n,&m)!= 0 && m && n)

        那么我们的代码也就可以顺势写出

#include <cstdio>
using namespace std;
int main(int argc, char *argv[])
{
	int m,n,kase=0;
	while (scanf("%d%d",&n,&m)!=0 && n && m)
	{
		double sum=0;
		for (int i=n;i<=m;i++){
			sum+=1.0/i/i;
		}
		printf("Case %d:%.5f\n",++kase,sum);
	}
	return 0;
}

p35-分数化小数

        简要题干:输入三个正整数a、b、c(a,b≤10的6次方,c≤100)

                          包含多组数据,结束标记为a=b=c=0。

                          输出a/b的小数形式,精确到前c位。

          我们还是先看数据类型,本题中最大输入数据10的6次方小于int的范围,而且运算最大数据小于10的6次方,所以int妥妥滴够                     

        我们接着分析,“输入包含多组数据。结束标记为n=m=0”这有通用的代码,即为

while(scanf("%d%d%d",&a,&b,&c)!= 0 && a && b && c)

但是这样子写代码可能不会通过输入测试!!!

例如 输入abc为2 2 0;或者输入abc为0 2 2;程序自动停止无法输出本次答案甚至之后的输入也被停止,我们要增强我们程序的健壮性和鲁棒性,以达到减少错误的目的。

本题除法的除数不为0,所以我们的代码这样子写.

while(scanf("%d%d%d",&a,&b,&c)!= 0  && b)

那么怎么输出c位小数呢?用不了%.f,我们只能循环迭代做处和取模的操作,模拟除法竖式。

所以代码如下:

#include <iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;

int main()

{

     int a,b,c;
     while(scanf("%d %d %d",&a,&b,&c)!=0&&b)
     {
         if(a==0)
         {
             printf("0\n");
         }
         else{
         if(c==0)
         {
             printf("%d\n",a/b);

         }
         else{
          int t[101]={0};
          int p[101]={0};
                t[0]=a/b;
                p[0]=a%b;
            int i=1;
            for(i;i<=c;i++)
            {
                t[i]=p[i-1]*10/b;//模拟竖式计算除法的*10
                p[i]=p[i-1]*10%b;


            }
            t[i]=p[i-1]*10/b;
            if(t[i]>=5)
            {

                t[i-1]++;
            }
            printf("%d",t[0]);

            printf(".");
            for(int i=1;i<=c;i++)
            {

                 printf("%d",t[i]);
            }
            printf("\n");


     }

}
}
    return 0;
}