《c++程序设计》课程设计报告
班级:数学类一班 学号:2018212830
报告人姓名:李祥尊
实验地点: 山东农业大学东校计算机实验室409
完成起止时间:2019年1月2日-2019年1月4日
1、Problem D(题组1)
简要题意:
Problem Description
对于表达式n^2+n+41,当n在(x,y)范围内取整数值时(包括x,y)(-39<=x<y<=50),判定该表达式的值是否都为素数。
Input
输入数据有多组,每组占一行,由两个整数x,y组成,当x=0,y=0时,表示输入结束,该行不做处理。
Output
对于每个给定范围内的取值,如果表达式的值都为素数,则输出"OK",否则请输出“Sorry”,每组输出占一行。
Sample Input
0 1
0 0
Sample Output
OK
解题思路:
看到题目,目的很明确。使用循环嵌套解决此问题,先使用一重循环得出给定区间内方程的范围,然后再使用一次循环依次判断区间内的数值是否都是素数。
细节处理:注意判断素数时应明确for(int k=2;k*k<=d;k++),减少循环次数。
源码:
#include<iostream>
using namespace std;
int main()
{
int x,y,i,d,f=0,l=0;
while(cin>>x>>y)
{
if(x==0&&y==0)
break;
else
{
for(i=x;i<y;i++)
{
d=i*i+i+41;
for(int k=2;k*k<=d;k++)
{
if((d%k)==0)
f++;
}
if(f==0)
l=l+1;
}
if(l==(y-x+1))
cout<<"OK"<<endl;
else
cout<<"Sorry"<<endl;
}
}
}
- 2、Problem E(题组1)
简要题意:
Problem Description
多项式的描述如下:
1 - 1/2 + 1/3 - 1/4 + 1/5 - 1/6 + ...
现在请你求出该多项式的前n项的和。
Input
输入数据由2行组成,首先是一个正整数m(m<100),表示测试实例的个数,第二行包含m个正整数,对于每一个整数(不妨设为n,n<1000),求该多项式的前n项的和。
Output
对于每个测试实例n,要求输出多项式前n项的和。每个测试实例的输出占一行,结果保留2位小数。
Sample Input
2
1 2
Sample Output
1.00
解题思路:
目的为计算这个数列的前N项和,显然需要使用一次循环计算相加的和。由题意可知N为奇数时为正值为偶数时为负值,可以通过if语句来实现这种变换规律。也可以通过使用POW函数来实现。
细节解决:题目要求输出时精确到小数点后两位通过以下语句来实现cout<<setiosflags(ios::fixed)<<setprecision(2)<<s;。
源码:
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
int m,n,i;
float s;
while(cin>>m)
{
while(m--)
{
s=0;
cin>>n;
for(i=1;i<=n;i++)
s=s+(1/((pow((-1),(i+1)))*i));
cout<<setiosflags(ios::fixed)<<setprecision(2)<<s;
cout<<endl;
}
}
return 0;
}
- 3、Problem F(题组1)
简要题意:
Problem Description
有一个长度为n(n<=100)的数列,该数列定义为从2开始的递增有序偶数,现在要求你按照顺序每m个数求出一个平均值,如果最后不足m个,则以实际数量求平均值。编程输出该平均值序列。
Input
输入数据有多组,每组占一行,包含两个正整数n和m,n和m的含义如上所述。
Output
对于每组输入数据,输出一个平均值序列,每组输出占一行。
Sample Input
3 2
4 2
Sample Output
3 6
3 7
解题思路:
显而易见使用循环语句来实现以固定的数量来输出数据,虽然思路简单但是实现起来却并不轻松。使用if语句和continue来实现。
源码:
#include<stdio.h>
int main()
{
int n,m,i,sum,num;
while(scanf("%d %d",&n,&m)!=EOF)
{
num=0;sum=0;
for(i=2;i<=n*2;i+=2)
{
sum+=i;
num++;
if(num==m&&(i!=n*2))
{
printf("%d ",sum/num);
num-=m;
sum=0;
}
}
if(sum==0&&num==0) continue;
printf("%d\n",sum/num);
}
}
4、Problem G(题组1)
Problem Description
青年歌手大奖赛中,评委会给参赛选手打分。选手得分规则为去掉一个最高分和一个最低分,然后计算平均得分,请编程输出某选手的得分。
Input
输入数据有多组,每组占一行,每行的第一个数是n(2<n<=100),表示评委的人数,然后是n个评委的打分。
Output
对于每组输入数据,输出选手的得分,结果保留2位小数,每组输出占一行。
Sample Input
3 99 98 97
4 100 99 98 97
Sample Output
98.00
98.5
解题思路:
定义一个数组,依次将数据输入但数组中去,然后用for循环语句得到数组中的最大值和最小值,然后再用一个for语句得到平均得分。
细节处理:
不用最值函数也可以使用sort来对数组内的数据进行排序,然后再通过for语句得到平均值。Sort在平常的使用中往往能起到意想不到的效果。
源码:
#include<stdio.h>
int main()
{
int n,i;double s,x,max,min;
while(~scanf("%d",&n))
{
scanf("%lf",&x);
s=max=min=x;
for(i=1;i<n;++i)
{
scanf("%lf",&x);
s+=x;
max=(x>max)?x:max;
min=(x<min)?x:min;
}
printf("%.2lf\n",(s-max-min)/(n-2));
}
return 0;
}
5、Problem I(题组1)
Problem Description
输入n(n<=100)个整数,按照绝对值从大到小排序后输出。题目保证对于每一个测试实例,所有的数的绝对值都不相等。
Input
输入数据有多组,每组占一行,每行的第一个数字为n,接着是n个整数,n=0表示输入数据的结束,不做处理。
Output
对于每个测试实例,输出排序后的结果,两个数之间用一个空格隔开。每个测试实例占一行。
Sample Input
3 3 -4 2
4 0 1 2 -3
0
Sample Output
-4 3 2
-3 2 1 0
解题思路:
这个题目可以说时一个排序题,使用冒泡排序法进行排序。让较大的那个数始终在右边。因为题目时要求比较绝对值的大小,所以我们可以通过比较数据平方的大小来实现。
细节分析:
关于排序还有很多种,冒泡排序是一种比较基础的方法。在语句下关于交换看数组之间的顺序可以通过swap来实现。
源码:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int a[101],i,j,t,n;
while(cin>>n&&n!=0)
{
for(i=0; i<n; i++)
cin>>a[i];
for(j=0; j<n; j++)
for(i=0; i<n-1-j; i++)
if(a[i]*a[i]<a[i+1]*a[i+1])
{
int t=a[i];
a[i]=a[i+1];
a[i+1]=t;
}
for(i=0; i<n-1; i++)
cout<<a[i]<<" ";
cout<<a[n-1]<<endl;
}
return 0;
}
6、Problem J(题组1)
Problem Description
有n(n<=100)个整数,已经按照从小到大顺序排列好,现在另外给一个整数x,请将该数插入到序列中,并使新的序列仍然有序。
Input
输入数据包含多个测试实例,每组数据由两行组成,第一行是n和m,第二行是已经有序的n个数的数列。n和m同时为0标示输入数据的结束,本行不做处理。
Output
对于每个测试实例,输出插入新的元素后的数列。
Sample Input
3 3
1 2 4
0 0
Sample Output
1 2 3 4
解题思路:
这个题也算是一个排序问题,通过多定义一个数组,将新的数据加入到数组的最后一位。然后再使用sort进行排序输出。
细节处理:
源码:
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n,m,a[102],i;
while(cin>>n>>m)
{
if(n==0 && m==0)
break;
else
{
for(i=0;i<=n-1;i++)
{
cin>>a[i];
}
a[n]=m;
sort(a,a+n+1);
for(i=0;i<=n-1;i++)
cout<<a[i]<<" ";
cout<<a[i];
cout<<endl;
}
}
return 0;
}
7、简要题意:Problem N(题组1)
Problem Description
HDOJ上面已经有10来道A+B的题目了,相信这些题目曾经是大家的最爱,希望今天的这个A+B能给大家带来好运,也希望这个题目能唤起大家对ACM曾经的热爱。
这个题目的A和B不是简单的整数,而是两个时间,A和B 都是由3个整数组成,分别表示时分秒,比如,假设A为34 45 56,就表示A所表示的时间是34小时 45分钟 56秒。
Input
输入数据有多行组成,首先是一个整数N,表示测试实例的个数,然后是N行数据,每行有6个整数AH,AM,AS,BH,BM,BS,分别表示时间A和B所对应的时分秒。题目保证所有的数据合法。
Output
对于每个测试实例,输出A+B,每个输出结果也是由时分秒3部分组成,同时也要满足时间的规则(即:分和秒的取值范围在0~59),每个输出占一行,并且所有的部分都可以用32位整数表示。
Sample Input
2
1 2 3 4 5 6
34 45 56 12 23 34
Sample Output
5 7 9
47 9 30
问题分析:
时分秒为60进制,分秒每满60就要进一位,时不需要。计算的时候从秒开始,避免发生错误,定义的量较多,注意区分。
细节处理:一定要从低位到高位进行转制。
源码:
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
while(n--)
{
int ah,am,as,bh,bm,bs;
cin>>ah>>am>>as>>bh>>bm>>bs;
int a,b,c;
c=(as+bs)%60;
b=((as+bs)/60+am+bm)%60;
a=((as+bs)/60+am+bm)/60+ah+bh;
cout<<a<<" "<<b<<" "<<c<<endl;
}
return 0;
}
8、Problem Q(题组1)
简要题意:
Problem Description
古希腊数学家毕达哥拉斯在自然数研究中发现,220的所有真约数(即不是自身的约数)之和为:
1+2+4+5+10+11+20+22+44+55+110=284。
而284的所有真约数为1、2、4、71、 142,加起来恰好为220。人们对这样的数感到很惊奇,并称之为亲和数。一般地讲,如果两个数中任何一个数都是另一个数的真约数之和,则这两个数就是亲和数。
你的任务就编写一个程序,判断给定的两个数是否是亲和数
Input
输入数据第一行包含一个数M,接下有M行,每行一个实例,包含两个整数A,B; 其中 0 <= A,B <= 600000 ;
Output
对于每个测试实例,如果A和B是亲和数的话输出YES,否则输出NO。
Sample Input
2
220 284
100 200
Sample Output
YES
NO
问题分析:
很容易就可以想到先使用穷举法得出二者的约数然后再相加进行比较,约束的得到通过for加if语句得到;
细节处理:当二者相等时不用进行计算直接得到结果YES;
源码:
#include<iostream>
using namespace std;
int main()
{
int n,i;
cin>>n;
while(n--)
{
int x,y,s=0,p;
cin>>x>>y;
if(x==y)
cout<<"YES"<<endl;
if(x>y)
p=x;
if(x<y)
p=y;
for(i=1;i<=p-1;i++)
{
if(p%i==0)
s=s+i;
}
if(s==(x+y-p))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
错误答案
#include<iostream>
using namespace std;
int main()
{
int n,i;
cin>>n;
for(i=1;i<n;i++)
{
int x,y,s=0,p;
cin>>x>>y;
if(x==y)
cout<<"YES"<<endl;
if(x>y)
p=x;
if(x<y)
p=y;
for(i=1;i<=p-1;i++)
{
if(p%i==0)
s=s+i;
}
if(s==(x+y-p))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
9、Problem P(题组1)
简要题意:
Problem Description
求A^B的最后三位数表示的整数。
说明:A^B的含义是“A的B次方”
Input
输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1<=A,B<=10000),如果A=0, B=0,则表示输入数据的结束,不做处理。
Output
对于每个测试实例,请输出A^B的最后三位表示的整数,每个输出占一行。
Sample Input
2 3
12 6
6789 10000
0 0
Sample Output
8
984
1
问题分析:
看到这个题目没有考虑数据范围的问题,直接进行计算。结果可想而知Wrong Answer。然后使用long long也是错误的。因为这个题目是求最后的三个整数,所以可以每一次计算后后%1000求最后三位来实现数据在范围之内;
细节处理:
防止数据超出范围。
源码:
#include<iostream>
using namespace std;
int main()
{
int n,m,i,x;
while(cin>>n>>m)
{
if(n==0 && m==0)
break;
x=1;
for(i=1;i<=m;i++)
{
x=(n*x)%1000;
}
cout<<x<<endl;
}
}
10、Problem R(题组1)
简要题意:
Problem Description
有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?
Input
输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1<=M<=40),表示楼梯的级数。
Output
对于每个测试实例,请输出不同走法的数量
Sample Input
2
2
3
Sample Output
1
2
问题分析:
首先看到这个题目时没有思路的,在演算纸上写出几组数据后可以观察到规律。然后使用数组得到结果。
细节处理:
对于这种题目很难知道什么直接性的解体方法,使用for if都难以解决,要先试几组数据找到规律,问题就迎刃而解了。
源码:
#include<iostream>
using namespace std;
int main()
{
int n,a[50],i,b;
cin>>n;
while(n--)
{
cin>>b;
if(b<=3)
{
a[1]=0;
a[2]=1;
a[3]=2;
}
else
{
for(i=4;i<=b;i++)
{
a[i]=(a[i-1]+a[i-2]);
}
}
cout<<a[b]<<endl;
}
}
11、Problem K(题组1)
简要题意:
Problem Description
作为杭电的老师,最盼望的日子就是每月的8号了,因为这一天是发工资的日子,养家糊口就靠它了,呵呵
但是对于学校财务处的工作人员来说,这一天则是很忙碌的一天,财务处的小胡老师最近就在考虑一个问题:如果每个老师的工资额都知道,最少需要准备多少张人民币,才能在给每位老师发工资的时候都不用老师找零呢?
这里假设老师的工资都是正整数,单位元,人民币一共有100元、50元、10元、5元、2元和1元六种。
Input
输入数据包含多个测试实例,每个测试实例的第一行是一个整数n(n<100),表示老师的人数,然后是n个老师的工资。
n=0表示输入的结束,不做处理。
Output
对于每个测试实例输出一个整数x,表示至少需要准备的人民币张数。每个输出占一行。
Sample Input
3
1 2 3
0
Sample Output
4
问题分析:
因为这个题目是算至少需要多是纸币,因此是面额越大的越好。所以从最高面额使用if语句来计算。
细节处理:
源码:
#include <iostream>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
if(n==0)
break;
int t,x=0;
while(n--)
{
cin>>t;
if(t>=100) x+=t/100,t%=100;
if(t>=50) x+=t/50,t%=50;
if(t>=10) x+=t/10,t%=10;
if(t>=5) x+=t/5,t%=5;
if(t>=2) x+=t/2,t%=2;
if(t==1) x+=t;
}
cout<<x<<endl;
}
return 0;
}
12、Problem A(题组2)
简要题意:
Problem Description
喜欢西游记的同学肯定都知道悟空偷吃蟠桃的故事,你们一定都觉得这猴子太闹腾了,其实你们是有所不知:悟空是在研究一个数学问题!
什么问题?他研究的问题是蟠桃一共有多少个!
不过,到最后,他还是没能解决这个难题,呵呵^-^
当时的情况是这样的:
第一天悟空吃掉桃子总数一半多一个,第二天又将剩下的桃子吃掉一半多一个,以后每天吃掉前一天剩下的一半多一个,到第n天准备吃的时候只剩下一个桃子。聪明的你,请帮悟空算一下,他第一天开始吃的时候桃子一共有多少个呢?
Input
输入数据有多组,每组占一行,包含一个正整数n(1<n<30),表示只剩下一个桃子的时候是在第n天发生的。
Output
对于每组输入数据,输出第一天开始吃的时候桃子的总数,每个测试实例占一行。
Sample Input
2
4
Sample Output
4
22
问题分析:
细节处理:
源码:
#include<stdio.h>
int main()
{
int i,n,sum;
while(scanf("%d",&n)!=EOF)
{sum=1;
if(n>1&&n<30)
for(i=1;i<n;i++)
{
sum=(sum+1)*2;
}
printf("%d\n",sum);
}
return 0;
}
13、Problem C(题组2)
简要题意:
Problem Description
这次xhd面临的问题是这样的:在一个平面内有两个点,求两个点分别和原点的连线的夹角的大小。
注:夹角的范围[0,180],两个点不会在圆心出现。
Input
输入数据的第一行是一个数据T,表示有T组数据。
每组数据有四个实数x1,y1,x2,y2分别表示两个点的坐标,这些实数的范围是[-10000,10000]。
Output
对于每组输入数据,输出夹角的大小精确到小数点后两位。
Sample Input
2
1 1 2 2
1 1 1 0
Sample Output
0.00
45.00
问题分析:
求角度问题可以使用数量积余弦公式处理。但是数量积要比余弦定理简单。
源码:
#include<cstdio>
#include<cmath>
#define PI acos(-1.0)
int main()
{
double x1,y1,x2,y2;
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
printf("%.2lf\n",acos((x1*x2+y1*y2)/(sqrt(x1*x1+y1*y1)*sqrt(x2*x2+y2*y2)))*180/PI);
}
return 0;
}
- 14、Problem D(题组2)
Problem Description
一个整数,只知道前几位,不知道末二位,被另一个整数除尽了,那么该数的末二位该是什么呢?
Input
输入数据有若干组,每组数据包含二个整数a,b(0<a<10000, 10<b<100),若遇到0 0则处理结束。
Output
对应每组数据,将满足条件的所有尾数在一行内输出,格式见样本输出。同组数据的输出,其每个尾数之间空一格,行末没有空格。
Sample Input
200 40
1992 95
0 0
Sample Output
00 40 80
15
题目分析:
首先将a补齐,a*1000,然后以a*1000+x整除b,然后依次输出x。本题的难点在a*1000+x整除b,而x<10时,需要以0x的形式输出。解决方案是写一个if语句以printf(“%0d”,x)。这样就解决了这个问题。第二个问题是题目要求同组数据的输出,其每个尾数之间空一格,行末没有空格。 这个问题同样用if语句来解决。当输出第一个数据的时候printf(“%d”,x)然后进入下一个语句scanf(“% d”,x)这样就解决了这个问题。
源码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a,b;
while(scanf("%d %d",&a,&b)&&a||b)
{
a=a*100;
int k=0;
for(int i=0;i<=99;i++)
{
if((a+i)%b==0)
{
k++;
if(k==1)
{
if(i<10)
{
printf("0");
printf("%d",i);
}
else
printf("%d",i);
}
else
{
if(i<10)
{
printf(" 0");
printf("%d",i);
}
else
printf(" %d",i);
}
}
}
printf("\n");
}
return 0;}
15、Problem U(题组1)
简要题意:
Problem Description
大家都知道,手机号是一个11位长的数字串,同时,作为学生,还可以申请加入校园网,如果加入成功,你将另外拥有一个短号。假设所有的短号都是是 6+手机号的后5位,比如号码为13512345678的手机,对应的短号就是645678。
现在,如果给你一个11位长的手机号码,你能找出对应的短号吗?
Input
输入数据的第一行是一个N(N <= 200),表示有N个数据,接下来的N行每一行为一个11位的手机号码。
Output
输出应包括N行,每行包括一个对应的短号,输出应与输入的顺序一致。
Sample Input
2
13512345678
13787654321
Sample Output
645678
654321
问题分析:
将电环号码当作一个11位的的数字,通过%100000求余数来得到电话号码的后五位,在将大的的余数加上600000,然后得到答案。经过测试这样是不对的。然后尝试使用数组进行解决。
细节处理:
高位除法在使用中可能会出现意想不到的问题。
源码:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
int n;
char str1[12];
char str2[7];
cin>>n;
while(n--)
{
cin>>str1;
str2[0]='6';
str2[1]=str1[6];
str2[2]=str1[7];
str2[3]=str1[8];
str2[4]=str1[9];
str2[5]=str1[10];
cout<<str2<<endl;
}
}
总结:
经过几天的程序设计课,写了挺多的代码,遇到了非常多的问题,同时也收获了许多。真正认识到了C语言与程序设计的魅力,同时也明白了知道与会之间的差距。虽然有些题目看着很简单,以为自己可以很快的解决,但是真正写的时候往往不是这样的。他牵扯到很多问题,一个程序是一个整体,牵一发而动全身。虽然程序设计很难,虽然对于我们数学专业来说大学时期的程序设计课已经结束了。但是希望自己可以在下学期的选修课ACM中坚持下来,克服困难,收获程序设计的魅力。