《c++程序设计》课程设计报告
题目一:
来源:设一
1002 Problem B
题目简述:“水仙花数”是指一个三位数,它的各位数字的立方和等于其本身,比如:153=13+53+3^3。输入数据有多组,每组占一行,包括两个整数m和n(100<=m<=n<=999)。输出的水仙花数必须大于等于m,并且小于等于n,如果有多个,则要求从小到大排列在一行内输出,之间用一个空格隔开;
如果给定的范围内不存在水仙花数,则输出no。
解题思路:判断水仙花数,在一个循环里,将区间内的每个数逐一判断,利用余数分离每一位数,进行判断即可。(较简单)
代码及部分说明:
#include<stdio.h>
main()
{
int m,n,i,a,b,c,s=0;
while(scanf("%d
%d",&m,&n)!=EOF)
{
for(i=m;i<=n;i++)
{
a=i/100;
b=(i%100)/10;
c=i%10;
if(aaa+bbb+ccc==i)
{
s+=1;
if(s==1)
printf("%d",i);
if(s!=1)
printf(" %d",i);
}
}
if(s==0)
printf(“no”);
printf("\n");
s=0;
}
return
0;
}
#include
using
namespace std;
int
main()
{
int m,n,i,a,b,c,s=0;
while(cin>>m>>n)
{
if(m==0&&n&&0)
break;
for(i=m;i<=n;i++)
{
a=i/100;
b=(i%100)/10;
c=i%10;
if(a*a*a+b*b*b+c*c*c==i)
{
s+=1;
if(s==1)
cout<<i; if(s!=1)
cout<<"
"<<i;
}
}
if(s==0)
cout<<"no";
cout<<endl;
s=0;
}
return
0;
}
对于蓝色区域:输出的格式问题:先判断输出数据的个数,大于一的时候先输出一个,后面的其他数据就先输空格,再输数据,格式就不会出错了。
题目二:
来源:设一
1004 Problem D
题目简述:表达式n^2+n+41,当n在(x,y)范围内取整数值时(包括x,y)(-39<=x<y<=50),判定该表达式的值是否都为素数。对于每个给定范围内的取值,如果表达式的值都为素数,则输出"OK",否则请输出“Sorry”。
解题思路:先自定义一个函数,用来判断素数。主函数内,借助布尔数组判断结果。循环内,每算出一个结果,就进行判断,只有全部是素数时,借助布尔变量输出OK即可。(较简单)
代码及部分说明:
#include
#include
using
namespace std;
int prime(int
a)
{
for(int i=2;i<=sqrt(a);i++)
{
if(a%i==0)
return 0;
}
return 1;
}
int
main()
{
int x,y,m=0;
bool c[100]={true};
while(cin>>x>>y,!(x0&&y0))
{
m=0;c[1]=true;
for(int i=1;i<=100;i++)
{
m=x*x+x+41;
if(prime(m)==0)
{
c[1]=false;break;
}
if(x==y)break;x++;
}
if(c[1]==false)
cout<<“Sorry”<<endl;
elsecout<<“OK”<<endl;
}
return 0;
}
蓝色部分是对每一个结果的判断,注意要有严密的逻辑思维,可以先在纸演示一下。
绿色部分就是利用布尔变量进行的输出,要学会这种方法。
题目三:
来源:设一
1006 Problem F
题目简述:定义从2开始的递增长度为n(n<=100)的数列,按照顺序每m个数求出一个平均值,如果最后不足m个,则以实际数量求平均值。编程输出该平均值序列。输入数据有多组,包含两个正整数n和m,输出一个平均值序列,每组输出占一行。
解题思路:利用while将数据输入,先假设最后不足m个,将能正好处理的个数和剩余数据的个数算出,利用这两个算出的结果进行后续的平均值处理,处理过程中的情况较多,if语句的选择就比较好用,但一定要分析全面。(一般)
代码及部分说明:
#include
using
namespace std;
int
main()
{
int n,m,i,j,k,sum=0,ave=1,p,q,w,e=0;
while(cin>>n>>m)
{
e=0;
p=n/m;
q=n%m;
for(i=1;i<=p;i++)
{
sum=0;
if(i==1)
{
for(j=2;j<=2*m;j+=2)
{sum+=j;}
ave=sum/m;
if(e==0)
cout<<ave;
else cout<<"
"<<ave;
e++;
w=j;
}
else
{
for(k=w;k<2*m+w;k+=2)
{sum+=k;}
ave=sum/m;
cout<<"
"<<ave;
w=k;
}
}
ave=1;
if(q==0)
{cout<<endl;}
else
{
sum=0;
for(i=w;i<q*2+w;i+=2)
{sum+=i;}
ave=sum/q;
cout<<"
"<<ave;
cout<<endl;
}
}
return 0;
}
绿色部分的处理是关键,有效简便了思考过程,不过比较繁琐。
黄色部分还是对输出格式的处理,与第一个类似。
题目四:
来源:设一
1008 Problem H
题目简述:有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。输入数据由多个测试实例组成,每个测试实例占一行,包括一个整数n(0<n<55),对于每个测试实例,输出在第n年的时候母牛的数量。
解题思路:典型的斐波那契额数列变形题,先找规律,从第一个,第二个,第三个找出,可以通过递推,循环即可;或者是通过数组赋值,每一个下标对应一个数,需要时调用输出即可。(难度一般)
代码及部分说明:
#include
using
namespace std;
int
main()
{
int n,a1=1,a2=2,a3=3,m=0;
while(cin>>n,n!=0)
{
if(n==1)
cout<<a1<<endl;
if(n==2)
cout<<a2<<endl;
if(n==3)
cout<<a3<<endl;
if(n>3)
{
m=0;a1=1;a2=2;a3=3;
for(int i=4;i<=n;i++)
{
m=a1+a3;
a1=a2;
a2=a3;
a3=m;
}
cout<<m<<endl;
}
}
return 0;
}
红色部分是对刚开始的赋值,便于后续的计算递推用。
绿色部分是递推关系,值得注意的是,每次大循环之前一定要对前几个值进行恢复,否则会输出错误(因为会累加)。
题目五:
来源:设一
1009 Problem I
题目简述:输入n(n<=100)个整数,按照绝对值从大到小排序后输出。
输入数据有多组,每组占一行,每行的第一个数字为n,接着是n个整数,n=0表示输入数据的结束,不做处理。 输出排序后的结果,两个数之间用一个空格隔开,各占一行。
解题思路:定义一个数组,然后直接循环赋值,之后用swap函数,先用if判断大小,用abs函数,直接在swap内判断即可,无需引入多于变量。之前用了一种比较麻烦的方法,想定义两个数组,a为原数,b为取绝对值之后的数,sort排序,再更换下标输出,后来经过判断,方法行不通,故作罢。(较简单)
代码及部分说明:
#include
#include<stdlib.h>
#include
using
namespace std;
int
main()
{
int a[105],n;
while(cin>>n,!(n==0))
{
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int j=n-1;j>=1;j--)
{
for(int i=1;i<=n;i++)
{
if(i==n)
break;
if(abs(a[i])<abs(a[i+1]))
swap(a[i],a[i+1]);
}
}
for(int i=1;i<=n;i++)
{
if(i!=n)
cout<<a[i]<<"
";
if(i==n)
cout<<a[i];
}
cout<<endl;
}
return 0;
}
绿色部分为主干部分,先判断绝对值大小,再决定是否交换,值得学习。
题目六:
来源:设一
10013 Problem M
题目简述:输入一个十进制数N,将它转换成R进制数输出。包含两个整数N(32位整数)和R(2<=R<=16,
R<>10),输出转换后的数,每个输出占一行。
解题思路:借助函数进行操作。构造函数,与现实中相同,用几进制就除以几,每一次的商正序存放在数组中,完成后再倒序输出。需要注意的是大于10的进制,定义一个包含A-F的字符型数组,if判断如果大于十,利用循环输出字母即完成工作。(一般)
代码及部分说明:
#include
#include<stdio.h>
#include
using
namespace std;
void
td(int n,int a);
char
ch[6]={‘A’,‘B’,‘C’,‘D’,‘E’,‘F’};
int
main()
{
int n,m;
while(scanf("%d",&n)!=EOF)
{
cin>>m;
td(n,m);
}
return 0;
}
void
td(int n,int a)
{
int
x[17],i,j,k=0;
if(n<0)
cout<<"-";
j=abs(n);
do
{
k++;
i=j%a;
j/=a;
x[k]=i;
} while(j!=0);
for(int
h=k;h>=1;h–)
{
if(x[h]<10)
cout<<x[h];
else
cout<<ch[x[h]-10];
}
cout<<endl;
}
蓝色部分是除数和存储,以便后面输出利用。
绿色部分是自定义函数的重中之重,巧妙的构思值得大家学习与借鉴。
题目七:
来源:设一
10015 Problem O
题目简述:求两个集合的差,每组输入数据占1行,每行数据的开始是2个整数n(0<=n<=100)和m(0<=m<=100),分别表示集合A和集合B的元素个数,然后紧跟着n+m个元素,前面n个元素属于集合A,其余的属于集合B. 每个元素为不超出int范围的整数,如果n=0并且m=0表示输入的结束,每组数据输出一行数据,表示A-B的结果,如果结果为空集合,则输出“NULL”,否则从小到大输出结果。
解题思路:首先是定义两个数组,赋值两个集合。然后利用双重循环判断重复的数,将其赋值为零,sort排序。最后循环加判断,引入一个变量看是否为空集,输出即可。(中等)
代码及部分说明:
#include
#include
int
a[105],b[105];
using
namespace std;
int
main()
{
int
m,n,i,j,k;
while(cin>>n>>m,!(n0&&m0))
{
k=0;
for(i=1;i<=n;i++)
cin>>a[i];
for(j=1;j<=m;j++)
cin>>b[j];
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(b[i]==a[j])
a[j]=0;
}
}
sort(a,a+n+1);
for(i=1;i<=n;i++)
{
if(a[i]!=0)
{
cout<<a[i]<<" ";
k++;
}
}
if(k==0)
cout<<“NULL”;
cout<<endl;
}
return 0;
}
蓝色部分为作差,将相同的去除。
绿色部分为输出且判断是否为空集。
黄色部分利用变量看是否为空集,输出。
题目八:
来源:设一
10016 Problem P
题目简述:求A^B的最后三位数表示的整数。输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1<=A,B<=10000),如果A=0, B=0,则表示输入数据的结束, 对于每个测试实例,请输出A^B的最后三位表示的整数,每个输出占一行。
解题思路:对于一般的数可以操作,十分简便,将后三位分离即可。而对于超内存的数则需要谨慎,只保留后三位即可,前面的位数一概舍去,只进行后三位的处理即可。(中等)
代码及部分说明:
#include
using
namespace std;
int
main()
{
long long int a,b,i;
while(cin>>a>>b,!(a0&&b0))
{
long long int s=1;
for(i=1;i<=b;i++)
s=(s*a)%1000;
cout<<s<<endl;
}
return 0;
}
红色部分即为仅仅后三位的处理,代码简单,但不太好想。
题目九:
来源:设一
10019 Problem S
题目简述:有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.计算蜜蜂从蜂房a爬到蜂房b的可能路线数。蜂房的结构如下所示。
输入数据的第一行是一个整数N,表示测试实例的个数,然后是N 行数据,每行包含两个整数a和b(0<a<b<50)。对于每个测试实例,请输出蜜蜂从蜂房a爬到蜂房b的可能路线数,每个实例的输出占一行。
解题思路:此题也是斐波那契数列变形,但要注意与之前奶牛与爬楼梯的区别,思路是自我演算出前几项的结果,递推时要注意循环的次数,比较难想,但也不困难,熟能生巧。(一般)
代码及部分说明:
#include
using
namespace std;
int
main()
{
long long int n,a,b,i,a1,a2,a3,m=0;
cin>>n;
while(n--)
{
cin>>a>>b;
if((b-a)==1)
cout<<“1”<<endl;
if((b-a)==2)
cout<<“2”<<endl;
if((b-a)==3)
cout<<“3”<<endl;
if((b-a)>3)
{
a1=1,a2=2,a3=3,m=0;
for(i=3;i<(b-a);i++)
{
m=a2+a3;
a2=a3;
a3=m;
}
cout<<m<<endl;
}
}
return 0;
}
蓝色部分为自我演算得出的答案,需要仔细。
绿色部分为每次初始赋值和循环次数的判定。
题目十:
来源:设一
10022 Problem V
题目简述:方程:Ai = (Ai-1 + Ai+1)/2 - Ci
(i = 1, 2, 3, … n),给出A0,
An+1, 和
C1, C2, …Cn.计算A1 输入多个测试数据,对于每组数据,先是一个正整数n,(n <= 3000); 然后是2个数a0, an+1.接下来的n行每行有一个数ci(i = 1,
…n);以文件结束符结束。对于每个测试实例,用一行输出所求得的a1(保留2位小数)。
解题思路:对于这种数列的问题,一定要先在纸面上演算,将通项公式推出,得到规律,每一项系数的分母都为(n+1),在最后输出的时候统一处理除(n+1)。对给出的常数系数进行循环处理,循环加和,最后减去即可。(需要数学功底,难度略大)
代码及部分说明:
#include
#include
using namespace
std;
int
main()
{
double a[3500],c[3500];
int n,i,j;
double b,s;
b=0.00,s=0.00;
while(cin>>n)
{
j=n;
cin>>a[0]>>a[n+1];
for(i=1;i<=n;i++)
cin>>c[i];
for(i=1;i<=n;i++)
{
s=s+j*c[i];
j--;
}
b=(n*a[0]+a[n+1]-s*2)/(n+1);
cout<<fixed<<setprecision(2)<<b<<endl;
s=0.00;
}
return 0;
}
蓝色部分为对c常数部分的系数处理,循环累加。
绿色部分为对结果的处理,直接输出结果即可。
题目十一:
来源:设二
1003 Problem C
题目简述:在一个平面内有两个点,求两个点分别和原点的连线的夹角的大小。夹角的范围[0,180],两个点不会在圆心出现。输入数据的第一行是一个数据T,表示有T组数据。每组数据有四个实数x1,y1,x2,y2分别表示两个点的坐标,这些实数的范围是
[-10000,10000]。对于每组输入数据,输出夹角的大小精确到小数点后两位。
解题思路:同样是数学,需要用数学函数的处理,用开根号是算边长,然后用余弦定理算出cos夹角的值,再用反余弦函数得到带Π的值,但要注意的是将Π除去,再乘以180,最后保持两位小数输出即可。(一般)
代码及部分说明:
#include
#include
#include
#include
using namespace std;
int main()
{
int t,i;
double a,b,c,d,m,n,o,l,p;
cin>>t;
for(i=1;i<=t;i++)
{
cin>>a>>b>>c>>d;
m=0.00,n=0.00,o=0.00,l=0.00,p=0.00;
m=sqrt(a*a+b*b);
n=sqrt(c*c+d*d);
o=sqrt((a-c)*(a-c)+(b-d)*(b-d));
l=(m*m+n*n-o*o)/(2*m*n);
p=acos(l)*180/3.1415926;
cout<<fixed<<setprecision(2)<<p<<endl;
}
return 0;
}
蓝色部分为两点之间的距离公式。
绿色部分为余弦定理公式。黄色部分为对结果的处理,十分关键,这是一细节处理。
题目十二:
来源:设二
1004 Problem D
题目简述: 一整数,知道前几位,不知道末二位,被另一个整数除尽了,求该数的末二位,输入数据有若干组,每组数据包含二个整数a,b(0<a<10000,10<b<100),遇到0 0则结束。 对每组数据,将满足条件的所有尾数在一行内输出,同组数据的输出,其每个尾数之间空一格,行末没有空格。
解题思路:先将整数扩大一百倍,再除已另一个整数得余数,后两位从0判断到99,但要注意个位数的输出,前面要加零。这就需要if加判断,这是其一;另外要注意输出的空格处理,同样就用if处理。最后就是if考虑的情况,一定要全面。(一般)
代码及部分说明:
#include
using
namespace std;
int
main()
{
int a,b,c,i,z;
while(cin>>a>>b)
{
if(a==0&&b==0)
{
break;
}
z=0;
c=a*100;
for(i=0;i<=99;i++)
{
if((c+i)%b==0)
{
z++;
if(z==1&&i>9)
cout<<i;
if(z==1&&i>=0&&i<=9)
cout<<“0”<<i;
if(z>1)
{if(i>9)
cout<<" "<<i;
if(i>=0&&i<=9)
cout<<" "<<“0”<<i;
}
}
}
cout<<endl;
}
return 0;
}
绿色部分为对空格输出的处理,蓝色部分为对输出个位数的处理,但考虑要全面。
题目十三:
来源:设二
1005 Problem E
题目简述: 把一个偶数拆成两个不同素数的和,有几种拆法。输入包含一些正的偶数,其值不会超过10000,个数不会超过500,若遇0,则结束。对应每个偶数,输出其拆成不同素数的个数,每个结果占一行。
解题思路:先定义一个判断素数函数供主函数判断用。在利用循环两边向中间逼近,用if判断是否符合条件输出。(中等)
代码及部分说明:
#include
using namespace std;
bool prime(int n)
{
if(n2 || n3)
return 1;
if(n%6!=1 && n%6!=5)
return 0;
for( int i=5;i*i<=n;i=i+6)
{
if(n%i==0 || n%(i+2)==0)
return 0;
}
return 1;
}
int main()
{
int n,i,t;
while(cin>>n)
{
t=0;
if(n==0)
{
return 0;
}
for(i=2;i<=n/2;i++)
{
if(prime(i)==1 && prime(n-i)==1
&& i!=n-i)
t++;
}
cout<<t<<endl;
}
}
红色部分即为两个素数相加是否为原数的判断,值得学习。
题目十四:
来源:设二
1006 Problem F
题目简述:一种有趣的四位数2992,它的十进制数表示,其四位数字之和为2+9+9+2=22,它的十六进制数BB0,其四位数字之和也为22,同时它的十二进制数表示1894,其四位数字之和也为22。输入含有一些四位正整数,如果为0,则输入结束。若n为Sky数,则输出“#n is a Sky Number.”,否则输出“#n
is not a Sky Number.”。
解题思路:输入一个数,同纸上演算一样,分别用十,十二,十六除以这个数,分别加和,然后进行比较即可。(一般)
代码及部分说明:
#include
using namespace std;
int main()
{
int
n,i,a,b,c,d,e,f,g,h,j;
while(cin>>n)
{
if(n==0)
break;
g=n;h=n,j=n;
a=0,b=0;
for(i=1;i<=4;i++)
{
a=n%10;
n=n/10;
b=b+a;
}
//cout<<b<<endl;
c=0,d=0;
for(i=1;i<=4;i++)
{
c=h%12;
h=h/12;
d=d+c;
}
//cout<<d<<endl;
e=0,f=0;
for(i=1;i<=4;i++)
{
e=j%16;
j=j/16;
f=f+e;
}
//cout<<f<<endl;
if(bd&&df)
cout<<g<<" is a Sky
Number."<<endl;
else cout<<g<<" is
not a Sky Number."<<endl;
}
return 0;
}
红色部分一定要在进入循环之前赋0。
蓝色部分即为输入的数,由于中间有处理,故这个数需要保存。
题目十五:
来源:设二
1008 Problem H
题目简述:三角形,每行包含一个字符和一个整数n(0<n<41),不同的字符表示不同的花纹,整数n表示等腰三角形的高。显然其底边长为2n-1。如果遇到@字符,则表示所做出来的样板三角形已经够了。每个样板三角形之间应空上一行,三角形的中间为空。显然行末没有多余的空格。
解题思路:三角形,先判断前一个是否输出完一个三角形,换行。
然后利用循环进行三角形的输出(与oj中矩形和菱形类似)(一般)
代码及部分说明:
#include
#include
using
namespace std;
int
main()
{
int n,s;
char a;
s=0;
while(cin>>a)
{
s++;
if(a=='@')
break;
else
{
cin>>n;
if(s>1)
cout<<endl;
for(int i=1;i<=n;i++)
{
for(int
j=1;j<=2*n-1;j++)
{
if(i+j==n+1||i==n||j-i==n-1)
cout<<a;
if(i+j!=n+1&&i<n&&j-i<n-1)
cout<<"
";
}
cout<<endl;
}
}
}
return 0;
}
红色为循环的结束;蓝色为一个三角形的输出完了,换行;绿色三角形的输出,加强理解即可。
总结:经过三天的程序设计实验,一学期学到的知识得到充分的提炼和总结,运用知识的能力得到显著提升。程序语言解决问题的方法从无到有,愈发的熟练,但还是有一些问题头绪很乱或者是无头绪;一方面是现实中无法用所学知识解决,从而无法用程序语言写出;另一方面是现实中解决出来,但还不会用程序语言写出来。对于过去的时间,所学知识还要熟练应用;以后的时间如果还想进一步提升就只能靠自学,将语言其他部分全部学会,这样程序就会更简单,快捷。最后,革命尚未成功,同志仍需努力。