《C++程序设计》课程设计报告
班级:数学类2
班学号:2018212754
报告人姓名: 张庆龙
实验地点:教学楼411
完成起止日期:2018.12.28到2019.1.4
课程设计1
Problem 1
1、题意:数列An=2n(n<=100)的一个偶数数列,要求每m个数输出一个平均值。最后如果不足m个,则按实际数量输出。
2、解题思路:首先将n个单位长度的数列存在数组里,结合循环进行求解。
如果n可以整除m时,可以直接进行每m个数进行求他的平均值,如果n除以m有余数则先算出除完后有几组可以直接运算,剩余不足m项的在用一个循环算出来。
3、解题细节处理:注意每次储存值求和值,使用完后应该重新赋为0,而且此题也需要输出最后一个数的时候去掉后面的空格,所以需要一个变量区分前边的数和后面的数字。
4、原码:
#include<stdio.h>
#include<math.h>
int main()
{
int n,m,a[10000],d;
while(scanf("%d %d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
{
a[i]=2*i;}
int g=0;
int c=0;
int x=0;
if(n%m==0)
{d=n/m;
for(int j=0;j<d;j++)
{int b=0;
for(int l=1;l<=m;l++)
{x=l+m*j;
b=b+a[x];}
c=b/m;
if(g==0)
{printf("%d",c);
g=1;}
else if(g==1)
printf(" %d",c);}
printf("\n");}
else if(n%m!=0)
{d=n/m;
for(int j=0;j<d;j++)
{int b=0;
for(int l=1;l<=m;l++)
{x=l+m*j;
b=b+a[x];}
c=b/m;
printf("%d ",c);}
for(int j=d*m+1;j<=n;j++)
{int b=0;
b=b+a[j];
c=b/(n-d*m);}
printf("%d\n",c);}}
}
5、总结:
由数列是偶数数列,首先把整个数列放在一个数组中,然后判断他的个数,分两种情况进行处理,而且注意行末没有空格。
Problem 2
1、题意:水仙花数,“水仙花数”是指一个三位数,它的各位数字的立方和等于其本身。对于每个测试实例,要求输出所有在给定范围内的水仙花数,就是说,输出的水仙花数必须大于等于m,并且小于等于n,如果有多个,则要求从小到大排列在一行内输出,之间用一个空格隔开;若不存在则输出no。
2、解题思路:输入水仙花的取值范围,让水仙花的三位数从初始值到末尾值的每一个数都进行处理,将这三位数分别通过求余算出来。进行题目要求的运算。最后判断这个范围里面有没有满足的数据。并输出满足的数据。
3、解题细节处理:要定义一个初始值为0的变量,每找到一个满足题意得数,他就加一,以便于最后判断到底有没有满足的数据。而且在输出数据的时候,最后一个数据的输出后面没有空格。要求用一个变量来限制。
4、原码:
#include<stdio.h>
#include<math.h>
int main()
{
int n,m,a,b,c,d,f;
while(scanf("%d %d",&n,&m)!=EOF)
{
f=0;
for(int i=n;i<=m;i++)
{
a=i/100;
c=i%10;
d=i%100;
b=d/10;
if(f==0&&i==a*a*a+b*b*b+c*c*c)
{
printf("%d",i);
f=1;
}
else if(f!=0&&i==a*a*a+b*b*b+c*c*c)
printf(" %d",i);
}
if(f==0&&n<m)
printf("no");
printf("\n");
}
return 0;
}
5、总结:
因为这个题的no的条件实在循环一边以后确定的,所以一定要将他放在循环外面。最后判断是否为no。而且注意每个数据输出的时候,最后一个数据后面没有空格,所以要做好。
Problem 3
1、题意:母牛生小牛,一头母牛在每年年初的时候生一只小母牛,而且小牛在第四个年头开始也开始生小母牛,依次循环问n年后有多少头母牛。
2、解题思路:取四个变量分别表示四个岁数的牛的数量,然后用一个循环表示年数,然后分年数为0,年数小于等于四,和年数大于四三种情况处理。每一次循环改变一次每一个岁数的牛的数量。
3、解题细节处理:主要是找到每年变化的牛的类型的数量的关系和规律,列出来就能求解。
4、原码: #include<stdio.h>
#include<math.h>
int main()
{
int a=0,b=0,c=0,d=0,n;
while(scanf("%d",&n)!=EOF)
{
if(n==0)
break;
else if(n<=4)
printf("%d\n",n);
else
{n=n-4;
a=b=c=d=1;
for(int i=1;i<=n;i++)
{
d=d+c;
c=b;
b=a;
a=d;}
printf("%d",a+b+c+d);
printf("\n");
}
}
}
5、总结:这个题技巧性比较强,主要是找出规律,进行求解,每年的小牛在下一年会变成属于另一种类型的小牛,直到最后变成了成年牛。
Problem 4
1、题意:输入n个数,然后按照他们的绝对值的大小进行排序,从大到小排序,并按照这个顺序输出原来的数。
2、解题思路:先把所有的数存在一个数组中,然后进行按照他们的绝对值进行排序要交换的排序方法把他们进行排序,因为这样可以把他们的下标记录下来,便与输出原来的数组。
3、解题细节处理:每一行的行末没有空格,所以还是用一个变量进行处理,区分最后一个数和前面的数字。
4、原码: #include<stdio.h>
#include<math.h>
int main()
{
int n,a[10000],l,d,i,j;
while(scanf("%d",&n)!=EOF)
{
if(n==0)
continue;
else
{int x=0;
for(i=1;i<=n;i++)
{scanf("%d",&a[i]);}
for(i=1;i<n;i++)
{
l=i;
for(j=i+1;j<=n;j++)
{
if(fabs(a[j])>fabs(a[l]))
l=j;}
if(l!=i)
{
d=a[i];
a[i]=a[l];
a[l]=d;}}
for(i=1;i<=n;i++)
{if(x==0)
{printf("%d",a[i]);
x=1;}
else
printf(" %d",a[i]);}}printf("\n");}
}
5、总结:这个问题主要是考察了排序的问题,但是在排序的时候不能用sort语句因为这样不仅改变了原来的数列数字,而且也改变了下标。最后输出的时候没有办法进行处理。
Problem 5
1、题意:判断一个数是不是回文串,回文串是指正读和反读都一样的字符串。
2、解题思路:用scanf语句输入一个字符串,然后用strlen语句算出这个字符串的长度,然后用循环判断相对应的字母是否相同,最后用一个变量判断他是不是回文串。
3、解题细节处理:注意在用字符串的时候家头文件cstring,然后用一个变量去判断一个字符串是不是回文串。
4、原码:
#include<stdio.h>
#include<cstring>
#include<math.h>
int main()
{
int n,m;
char a[10000];
scanf("%d",&n);
for(int l=0;l<n;l++)
{scanf("%s",a);
m=strlen(a);
int c=0;
for(int i=0,j=m-1;i<j;i++,j--)
if(a[i]!=a[j])
{
c=1;
break;
}
if(c==0)
printf("yes\n");
else
printf("no\n");}
}
5、总结:输出字符串的时候可以用scanf直接输入一个字符串,计算一个字符串的长度的时候用strlen语句。
Problem 6
1、题意:输入一个十进制的数字,然后让他用R进制输出。
2、解题思路:分三种情况,如果输入的是负数的时候则把负号先输出,然后再把负数变为正数进行处理。如果输入的是0的时候则直接输出0,其他的情况的时候,先用一个循环把改变进制后的每一位数字输入进一个数组中,然后把他们输出出来。
3、解题细节处理:在改变进制的时候,原来的数与新的进制求余以后就会得到每一位数,然后把这个数除以新的进制在进行处理就行了。还有如果一个数存入数组的时候大于10就要用大写字母ABC…表示,这时候就要用转换思想。
4、原码:
#include<stdio.h>
#include<math.h>
int main()
{
int n,m;
while(scanf("%d %d",&n,&m)!=EOF)
{ if(n<0)
{
printf("-");
n=-n;
}
if(n==0)
{printf("0");
continue;}
int c=1,a[10000];
while(n!=0)
{
a[c]=(n%m);
n=n/m;
c++;}
for(int j=c-1;j>=1;j--)
{if(a[j]>=10)
{printf("%c",'A'-10+a[j]);
}
else
printf("%d",a[j]);}
printf("\n");
}
}
5、总结:改变进制的时候用一个求余,一个除法的循环就可以得到每一位的数字。以及字符和数字的转变。可以自动转变。
Problem 7
1、题意: A-B求的是两个集合的差,就是做集合的减法运算
2、解题思路:输入两个集合,并把它们分别放在两个数组里面,用一个两重循环,用大循环数组的每一个元素和另一个数组的每一个元素比较,如果相同的话就把它变成零。如果不同则不变。最后把这个新弄好的数组排序,如果他最后一个元素都为0的话则输出NULL,否则的话判断每个元素如果不为零话,则输出这个元素。
3、解题细节处理:在处理这个函数的时候用排序sort函数,注意sort函数的用法,后面的第n个元素必须在规定的时候用n+1。用goto语句的时候注意跳出的位置。
4、原码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int a[101],b[101];
int main()
{
int n,m,i,j,x,y;
while (cin>>n>>m)
{
if(n==0&&m==0)
break;
for(i=1;i<=n;i++)
{
cin>>x;
a[i]=x;
}
for(i=1;i<=m;i++)
{
cin>>x;
b[i]=x;
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(b[j]==a[i])
a[i]=0;
}
}
sort(a+1,a+n+1);
if(a[n]==0)
{cout<<"NULL"<<endl;
goto loop;}
for(i=1;i<=n;i++)
{
if(a[i]!=0)
cout<<a[i]<<' ';
}
cout<<endl;
loop: memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
}
}
5、总结:用了sort函数和memset函数,便于把一个数组清零,以后尽量少用goto语句。
Problem 8
1、题意:计算一只蜜蜂在蜂房中的路径的数量,只可以向右走,不过可以向右,也可以向右下走,所以每一步分两种情况,计算一共的方法数量。
2、解题思路:这个题属于阶梯类型的题目,每一步都分为两种情况,但是有一种递归的规律,比如从一到四就是从一到二和从一到三的加和。不过我们要先规定数组中前三个变量的值为0 1 2;因为他们一开始不满足。最后用数组坐标之间的减法就行了。
3、解题细节处理:定义方法数的时候我们要把这个数组定义为long long int 因为如果数字足够大时候,就越界了,无法真正的输出正确的结果。以及对于下标的改变的处理,看自己定义的数组从1开始还是从0开始。
4、原码:
#include<stdio.h>
#include<math.h>
int main()
{
int n,a,b;
long long int x[10000];
while(scanf("%d",&n)!=EOF)
{
x[1]=0;
x[2]=1;
x[3]=2;
for(int i=1;i<=n;i++)
{scanf("%d %d",&a,&b);
for(int j=4;j<=b;j++)
x[j]=x[j-1]+x[j-2];
printf("%lld\n",x[b-a+1]);}
}
}
5、总结:
递归的思想的处理。观察每一个取值是否和前面的取值有关系,然后进行处理,最后写出一个公式,把所有的情况包括进去,但是这个题的起点不固定。所有还要考虑起点的问题。
Problem 9
1、题意:老师发工资最少需要多少张纸币。
2、解题思路:先输入一个数字n表示有n个老师,再输入他们的工资并且存在一个数组里面,然后把五种面值的纸币存在一个有五个元素的数组里面,100 50 10
5 2 1,然后用一个双层的循环,进行处理,每次先从大的面额的纸币开始处理,然后用一个数字来记录纸币的数量。
3、解题细节处理:在把另一个存放面额的数组定义的时候一定要按照那个顺序,因为这样一会儿处理的时候才会好弄,处理的时候让每个老师的工资在处理的时候除以相应的面额,并且每次增加的数量是整除的数量。
4、原码:
#include<stdio.h>
#include<math.h>
int main()
{
int n,a[1000],b[6]={100,50,10,5,2,1};
while(scanf("%d",&n)!=EOF)
{
if(n==0)
break;
else
{int sum=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=0;j<6;j++)
{sum=sum+a[i]/b[j];
a[i]%=b[j];}
printf("%d\n",sum);}
}
}
5、总结:处理数据的时候要尽量的简单,想好每次的除余和整除以后的数字是什么。写好数据。
Problem 10
1、题意:方程:Ai = (Ai-1 + Ai+1)/2 - Ci (i = 1, 2, 3, .... n).若给出A0, An+1, 和 C1, C2, .....Cn. 编程计算A1 = ?
2、解题思路:分别计算A1,A2,A3…AN,最后把所有的式子加和,约去多余的项数,最后留下的只有a0,an+1,关于C的式子,就可以对a1进行求解。最后把a1的通式写出来就行了。
3、解题细节处理:主要是在列式子的时候对于a1的处理非常巧妙。定义各类数据的时候要把他们定义为double类型。最后输出的时候保留两位小数。对于每个变量C前面的系数的处理很巧妙。
4、原码:
#include<stdio.h>
#include<math.h>
int main()
{
int n;
double a1,a0,ax,a[10000],b[10000];
while(scanf("%d",&n)!=EOF)
{
int h=0;
scanf("%lf",&a0);
scanf("%lf",&ax);
for(int i=1;i<=n;i++)
{scanf("%lf",&a[i]);
b[i]=a[i]*(n-i+1);
h=h+b[i];}
a1=(ax+n*a0-2*h)/(n+1);
printf("%.2lf",a1);
printf("\n");
}
}
5、总结:一定要对数学式子有一定的敏感,多写几个式子找规律,通过加和求解,消去多余的未知量,最后求解。
Problem 11
1、题意:已知一个平面内的两个点,求这个两个点之间的夹角的度数,并保留两位小数。
2、解题思路:已知两个点的坐标,根据坐标点乘的公式,两个坐标的点乘等于两个点分别的mo乘以连个坐标之间夹角的cos值,所以我们需要求出两个点的点乘和分别得mo就行了。
3、解题细节处理:要明白一个反三角函数acos,asin,atan,分别求出他们的cos值,根据反三角函数就能求解。以及要保证取两位小数。
4、原码:
#include<stdio.h>
#include<math.h>
double PI=3.1415926;
int main()
{
int n;
double x1,x2,y1,y2;
double j,m,jiao;
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
j=x1*x2+y1*y2;
m=sqrt(x1*x1+y1*y1)*sqrt(x2*x2+y2*y2);
printf("%.2lf\n",acos(j / m) / PI*180.0);}
}
}
5、总结:
明确反三角函数的使用,在定义的时候要明白他们这些数值是double型的。
Problem 12
1、题意:坐过山车问题,根据每个女孩的要求选出最多的方案。
2、解题思路:因为每一个女孩的要求都不同,所以先把每一个女孩作为数组的基础,把他们选男生作为搭档的标准作为每一组数组的元素,然后利用集合元素比较的方法,从元素最多的那个开始,把里面与其他相同的元素都踢出去,最后留下自己为力的标准,如果全部相同则踢出去。
3、解题细节处理:注意在用循环的时候会超时,比较的数据太多。还有一种情况你要考虑到,就是求出来的种类数目,多余男孩的数目时,直接输出男孩的数目,而不是种类数。
4、原码:
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;
int map[510][510];
int visit[510];
int f[550];
int n,m;
int dfs(int cur)
{
int i;
for(i=1;i<=n;i++)
{
if(!visit[i]&&map[cur][i])
{
visit[i]=1;
if(!f[i]||dfs(f[i]))
{
f[i]=cur;
return 1;
}
}
}
return 0;
}
int hungary()
{
int i,ans=0;
for(i=1;i<=m;i++)
{
memset(visit,0,sizeof(visit));
ans+=dfs(i);
}
return ans;
}
int main()
{
int i,k,a,b;
while(true)
{
scanf("%d",&k);
if(k==0)
{
break;
}
scanf("%d%d",&m,&n);
memset(map,0,sizeof(map));
memset(f,0,sizeof(f));
for(i=0;i<k;i++)
{
scanf("%d%d",&a,&b);
map[a][b]=1;
}
cout<<hungary()<<endl;
}
return 0;
}
5、总结:注意使用循环的时候一定不能超时。四重循环很容易就超时了,可以先比较数组的元素的大小。在进行处理。
Problem 13
1、题意: 把一个字符三角形掏空,就能节省材料成本,减轻重量,但关键是为了追求另一种视觉效果。在设计的过程中,需要给出各种花纹的材料和大小尺寸的三角形样板,通过电脑临时做出来,以便看看效果。
2、解题思路:找出每一个图形的输出的规律。当行列数满足i+j=n+1或者j=n+i-1时输出那个图形,如果不是的话则输出空格,就可以满足这个图形,但是最后一行不一样,要主要考虑。
3、解题细节处理:最后一行可以和前面的几行分开考虑,后面的几行不一样。而且每两个图形之间要有一行空格,所以必须要保证有这样一行空格。而且要注意如果输入的是@则结束。
4、原码:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
char a;
int b,j,i,flag=1;
while(cin>>a)
{
if(a=='@')
break;
else
{
cin>>b;
if(flag!=0)
flag=0;
else
cout<<endl;
for(i=1;i<=b;i++)
{
if(i==b)
{
for(j=1;j<=2*b-1;j++)
cout<<a;
}
else
{
for(j=1;j<=2*b-1;j++)
{
if(j==b+1-i||j==b+i-1)
cout<<a;
else if(j<b+i-1)
cout<<" ";
else break;
}
}
cout<<endl;
}
}
}
}
5、总结:这个题一定要注意换行的保证,用一个变量去保证每一行之间的换行,以及两个图形之间的换行。要培养一种找规律的思维。
Problem 14
1、题意: 把一个偶数拆成两个不同素数的和
2、解题思路:输入一个偶数,把这个偶数用一个循环拆成两个不同的数。然后用一个函数去判断两个数是不是同时为素数,然后有一个初始值为0的变量去计数他们的个数,最后输出
3、解题细节处理: 但是要保证他从3开始,因为1不是素数,而2是素数中为一个偶数。所以在循环的时候从三开始到二分之n,每次加2。这样可以避免错误和重复。
4、原码:
#include<stdio.h>
#include<math.h>
int qs(int n)
{
for (int i=2; i<=sqrt(n); i++)
{
if (n%i==0)
return 0;
}
return 1;
}
int main()
{
int n;
int a,b;
while(scanf("%d",&n)!=EOF)
{
int z=0;
if(n==0)
continue;
for(int i=3;i<n/2;i+=2)
{
a=i;
b=n-i;
if(qs(a)&&qs(b))
z++;
}
printf("%d",z);
printf("\n");
}
}
5、总结:对素数要有一定的了解,除了自己和一以外没有别的数可以整除他。明白优化循环中的条件。方便不会有重复。
Problem 15
1、题意: 有二个整数,它们加起来等于某个整数,乘起来又等于另一个整数,他们是不是存在?
2、解题思路:输入进去两个数的和和乘积,用一个循环以及用两个数把和拆开,拆成两个数。如果两个数的乘积等于你输入的那个数的话,就输出yes,否则输出no。
3、解题细节处理:注意要把情况全部考虑进去,比如乘积为零的情况,一个数为负数的情况,两个数为负数时,循环必须从负数开始。
4、原码:
#include<stdio.h>
#include<math.h>
int main()
{
int n,m,a[10000],b[10000];
while(scanf("%d %d",&n,&m)!=EOF)
{
int z=0;
if(n==0&&m==0)
continue;
else
{
for(int i=-fabs(n);i<=fabs(m);i++)
{a[i]=n-i;
b[i]=i;
if(a[i]*b[i]==m)
{z=1;
break;}}
if(n-m!=0&&z==1||m==0)
printf("Yes\n");
else if(z==0||m-n==0)
printf("No\n");}}}
5、总结:要对一个题的所有情况掌握清楚。所有情况都要考虑进去。避免漏掉很巧妙的情况。
学业总结:时间很快。转眼间已经学了半年的c语言了。对于c语言从一开始的好奇。到后来的一点点的明白。再到渐渐的开始感兴趣。觉得c语言对我们的学习真的很有帮助。不管是这种思维还是在解题过程中学会的新的概念和数学公式。对我们以后的学习都有很大的帮助。对自己的学习也是比较满意的。尽管有的时候喜欢借鉴别人的代码。但是从来没有直接抄的时候。都会自己先想。然后自己一点一点的提升进步。到现在可以比较容易的写出几个代码。感觉我自己收货了很多。在这里也特别感谢老师的帮助和教导。日后如果在接触c语言我相信一定有比较好的基础了。