C++程序设计课程设计论文

《c++程序设计》课程设计报告论文班级:数学3班 学号:2018212790报告人姓名:朱泳基 实验地点:东校区教学楼413完成起止日期: 2019年1月2号到1月5号①简要题意:有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛? 解题思路:这道题问第几年有几头牛,首先看输入输出,可以知道当年数小于等于4的时候,第几年就有几头牛,当n大于4的时候,这时候第一年出生的小母牛又可以生小牛了,也就是说要考虑到小牛是否可以生了。每年都有有a(n-1)头母牛,那么就要知道这一年出生的母牛有多少。第n-3年有多少头母牛,到了第n年这些牛都能生小牛了,因此出生数a(n-3。 从而今年的母牛数为a(n)=a(n-1)+a(n-3)。因此得到递推公式:a(1)=1,a(2)=2,a(3)=3,a(n)=a(n-1)+a(n-3)(n>=4)。解题细节:只要弄清题意,找到规律a(1)=1,a(2)=2,a(3)=3,a(n)=a(n-1)+a(n-3)(n>=4),就行了。原码:#include int a[60];//开的稍微大一点int main(){ int n; a[1] = 1; a[2] = 2; a[3] = 3; a[4] = 4; for(int i=5;i <= 60;i++) a[i] = a[i-1] + a[i-3]; while(~scanf("%d",&n) && n != 0){//等价于scanf("%d",&n) != EOF printf("%d\n",a[n]); } return 0;o}②简要题意:有一个长度为n(n<=100)的数列,该数列定义为从2开始的递增有序偶数,现在要求你按照顺序每m个数求出一个平均值,如果最后不足m个,则以实际数量求平均值。编程输出该平均值序列。解题思路:数列:2,4,6,8,10,12,14,16,18,20,22,24 …… 2n每 m 个数求出一个平均值,即求这 m 个数中的“第一个数和最后一个数的平均值”.假设 q = n /m ; r = n % m ;(q = 1,2,3,4 …… ; r = 0,1,2,3 …… ;即数列可分成 q 组余 r 个数) 则:m 个数一组的时候:第一个数:2 * [ ( q -1) * m + 1 ] 。最后一个数:2 * q * m 平均值:2 * q * m - m + 1最后不足 m 个数的时候:第一个数:2 * [ ( q -1) * m + 1 ] 最后一个数:2 * [ ( q -1) * m + r ] 平均值:2 * q * m - 2 * m + r + 1原码: #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<=n2;i+=2) { sum+=i; num++; if(num==m&&(i!=n2)) { printf("%d “,sum/num); num-=m; sum=0; } } if(sum0&&num0) continue; printf(”%d\n",sum/num); }}③简要题意有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?解题思路:因为最后一步可以跨一个可以跨两个,跨上第n台阶的等于跨上第n-1台阶的数量+跨上第n-2台阶的数量。解题细节:斐波那契数列 f(n)=f(n-1)+f(n-2);由于后续数据较大,所以要用__int64类型,否则会因溢出而导致WA,还有使用printf输出时应是"%I64d"。原码:#include<stdio.h> int main() { int N=0,M=0,i=0,sum=0,a[41]={0}; scanf("%d",&N); a[1]=1; a[2]=1; for(i=3;i<=40;i++) //将前40个数储存起来 a[i]=a[i-1]+a[i-2]; while(N–) { scanf("%d",&M); printf("%d\n",a[M]); } return 1; }总结:方程求解,第一是想到递归。可是递归的时间复杂度太大,题目中说的是你现在已经是站在第一级上了.我们在写程序的时候后退一步,假设人在第0级。那么这时候我们就很容理解为什么dp[1]1dp[2] == 2了。单数这时候需要注意的是题目中说的上到底3级,其实也就是上到我们程序中所说的第2级。这是需要注意的.这也是为什么输出最后的结果是dp[n-1]了④简要题意:输入一个十进制数N,将它转换成R进制数输出。解题思路:十进制的数转成二进制,最常用的方法,就是除R取余法,将十进制的数n除以R取其余数,这里得到的余数是R进制数的最后一位。比如:7转化为2进制,先用7%2得到的是1,这里的1是转化后的二进制数的最后一位,再接着,令n=n/R,即为除得的整数结果(注意,这里的n需要大于0,因为后续会产生重复的操作),同上例n=7/2=3;再同以上的方法将,3%2=1作为2进制数的倒数第二位。以此类推,2进制数的倒数第三位等于3/2%2=1;这时n=0了,循环到此终止,二进制的数为111(注意是从第1位读到最后一位),即是说,代码实现时需要逆序输出(这里很容易想到用数组来存取每一个余数)。逆序输出我们很熟悉,若R进制的数共有X位,令n=X-1;n往下移动一位一直到n=0,对数组进行输出。for循环可以方便的实现。到此一个十进制的数转化成10进制以内任意R进制功能就实现了。在接下来,考虑11到16进制的转化,很明显,因为有了字母的引入。不能直接对于数组进行直接的输出。这里,可以使用switch case 或者是if语句。倒顺序的每次判断均输出一个结果,输出结束别忘了加上\n换行。解题细节:PS别忘了对于0以及负数的单独判断。负数先转换为正数,按以上的方法输出后,再加上一个符号位(这里的符号位要在最开始输出);0则是直接等于0;原码:#include<stdio.h>#include<string.h>int main(){ int n,r,i; while(scanf("%d %d",&n,&r)!=EOF) { if(n<0) { printf("-");n=-n; } if(n0){printf(“0\n”);continue;} int c=0,a[100]; while(n) { a[c]=(n%r); c++; n/=r; } for(i=c-1;i>=0;i–) { if(a[i]>=10) { printf("%c",‘A’+a[i]-10); } else printf("%d",a[i]); } printf("\n"); }}总结:要熟悉进制之间的转换。⑤简要题意:有如下方程:Ai = (Ai-1 + Ai+1)/2 - Ci (i = 1, 2, 3, … n).若给出A0, An+1, 和 C1, C2, …Cn.请编程计算A1 = ? 解题思路:因为:Ai=(Ai-1+Ai+1)/2 - Ci, A1=(A0 +A2 )/2 - C1; A2=(A1 + A3)/2 - C2 , … => A1+A2 = (A0+A2+A1+A3)/2 - (C1+C2) => A1+A2 = A0+A3 - 2(C1+C2) 同理可得: A1+A1 = A0+A2 - 2(C1) A1+A2 = A0+A3 - 2(C1+C2) A1+A3 = A0+A4 - 2(C1+C2+C3) A1+A4 = A0+A5 - 2(C1+C2+C3+C4) … A1+An = A0+An+1 - 2(C1+C2+…+Cn) ----------------------------------------------------- 左右求和 (n+1)A1+(A2+A3+…+An) = nA0 +(A2+A3+…+An) + An+1 - 2(nC1+(n-1)C2+…+2Cn-1+Cn) => (n+1)A1 = nA0 + An+1 - 2(nC1+(n-1)C2+…+2Cn-1+Cn) => A1 = [nA0 + An+1 - 2(nC1+(n-1)C2+…+2Cn-1+Cn)]/(n+1) 解题细节:原码:#include #include #include #include using namespace std;const int maxn=3000+10;double c[maxn];int main(){ int n; double A0,An; while(scanf("%d",&n)!=EOF) { scanf("%lf%lf",&A0,&An); double sum=0.0; for(int i=1;i<=n;i++) { scanf("%lf",&c[i]); sum+=(n-i+1)c[i]; } double A1 = (nA0+An-2*sum)/(n+1); printf("%.2lf\n",A1); } return 0;}⑥第一天吃掉了所有桃子总数一半多一个,第二天又将剩下的桃子吃掉一半多一个,以后每天吃掉前一天剩下的一半多一个,到第n天准备吃的时候只剩下一个桃子。第一天开始吃的时候一共有多少个桃子?解题思路、解题细节最后剩下一个 ,每天都吃前一天剩下的一半多一个,倒着推呗。源代码#include <bits/stdc++.h>using namespace std;int main(){ int n; while (cin>>n) { if (n==0) break; int i,c=1; for (i=n;i>1;i–) c=(c+1)*2; cout<<c<<endl; } return 0;}⑦输入数据的第一行是三个整数K , M , N,分别表示可能的组合数目,女生的人数,男生的人数。0<K<=1000 ,1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。 Output对于每组数据,输出一个整数,表示可以坐上过山车的最多组合数。 首先需要讲下匈牙利算法的基本思想,因为书上的确实很让人看着烦躁,所以从网上找了一个简明易了的。匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名。匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。-------等等,看得头大?那么请看下面的版本:通过数代人的努力,你终于赶上了剩男剩女的大潮,假设你是一位光荣的新世纪媒人,在你的手上有N个剩男,M个剩女,每个人都可能对多名异性有好感(-_-||暂时不考虑特殊的性取向),如果一对男女互有好感,那么你就可以把这一对撮合在一起,现在让我们无视掉所有的单相思(好忧伤的感觉),你拥有的大概就是下面这样一张关系图,每一条连线都表示互有好感。本着救人一命,胜造七级浮屠的原则,你想要尽可能地撮合更多的情侣,匈牙利算法的工作模式会教你这样做:===============================================================一: 先试着给1号男生找妹子,发现第一个和他相连的1号女生还名花无主,got it,连上一条蓝线二:接着给2号男生找妹子,发现第一个和他相连的2号女生名花无主,got it三:接下来是3号男生,很遗憾1号女生已经有主了,怎么办呢?我们试着给之前1号女生匹配的男生(也就是1号男生)另外分配一个妹子。(黄色表示这条边被临时拆掉)与1号男生相连的第二个女生是2号女生,但是2号女生也有主了,怎么办呢?我们再试着给2号女生的原配()重新找个妹子(注意这个步骤和上面是一样的,这是一个递归的过程) 此时发现2号男生还能找到3号女生,那么之前的问题迎刃而解了,回溯回去2号男生可以找3号妹子~~~ 1号男生可以找2号妹子了~~~ 3号男生可以找1号妹子所以第三步最后的结果就是:四: 接下来是4号男生,很遗憾,按照第三步的节奏我们没法给4号男生腾出来一个妹子,我们实在是无能为力了……香吉士同学走好。这就是匈牙利算法的流程,其中找妹子是个递归的过程,最最关键的字就是“腾”字。这便是匈牙利算法的思想。代码:#include using namespace std;const int N = 505;bool map[N][N], flag[N];int pre[N];int n, m, num;//匈牙利算法(二分图算法) int find(int cur) //cur为当前女生 { int i; for (i = 1; i <= m; i++) //被匹配的男生 { if (map[cur][i] && !flag[i]) //该男生未被匹配 并且被女生选中 { flag[i] = true; //这次匹配中,标记该男生已匹配 if (pre[i] == -1 || find(pre[i]))//该男生没有被女生匹配 or 匹配了该男生的女生继续找其他男生 -> ok { pre[i] = cur; //男生[i]跟女生cur配对了 return 1; } } } return 0;}int main(){ int i, girl, boy, sum; while (cin>>num) { if(!num)return 0; cin>>n>>m; //n是女生数量,m是男生数量 memset(map, false, sizeof(map)); memset(pre, -1, sizeof(pre)); for (i = 0; i < num; i++) { cin>>girl>>boy; map[girl][boy] = true; //可以匹配 } sum = 0; for (i = 1; i <= n; i++) //女生去匹配男生 { memset(flag, 0, sizeof(flag)); //每次重新标记0 sum += find(i); } cout<<sum<<endl; } return 0;}⑧ 已知两点坐标要求其到原点连线的夹角,那么我们可以用向量去做,用向量的积除以向量模的乘积,在求其反函数,然后转换为角度就可以知道其角度为多少了;解题细节:向量的模的乘积 sqrt(x2+y2);向量的乘积 x1x2+y1y2;源码:#include#includeusing namespace std;#define PI 3.1415967int main(){ double x1, x2, y1, y2; double mo, ji; int t; scanf("%d", &t); while (t–) { scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); mo = sqrt(x1x1 + y1y1)sqrt(x2x2 + y2y2); ji = x1x2 + y1y2; printf("%.2lf\n", acos(ji / mo) / PI180.0); } return 0;}⑨ 如果两个数中任何一个数都是另一个数的真约数之和,则这两个数就是亲和数。解题思路:用一个一维数组记录下来所输入的数,并且将其真约数的和记录下来,判断与另一个数是否相等,反之一次,如果均相等给出YES,否则NO。解题细节:源码:#includeusing namespace std;int main(){ int s; cin>>s; while(s–) { int i,n,a,b; cin>>a>>b; int sum=0,m=0; for(i=1; i<a; i++) { if(a%i0) { sum+=i; } } for(n=1; n<b; n++) { if(sum%n0) { m+=n; } } if(ma&&sumb) cout<<“YES”<<endl; else cout<<“NO”<<endl; }return 0;}⑩简要题意:把一个偶数拆成两个不同素数的和 解题思路:两个不同的素数加和等于给出的偶数.就算是一种方式 问一共有多少种方式.首先我们看到题马上就会有一个for循环的思路去判断小于n的素数.如果是素数 再去找另外一个素数.令a=n-当前素数,然后判断a是否是素数就行了.推论到这里我们有一个for循环能够解决当前问题:for(int i=3;i<n;i++){ if(isprime(i)&&isprime(n-i))output++;}但是这里有个问题:方式会重复 那么我们就需要/2的操作之类的繁琐判断过程 所以我们要优化.1.我们知道偶数不可能是素数2.我们知道如果两个素数不同.一定是一个素数小于t/2一个素数大于t/2没有任何其他实例反驳掉这个结论之后我们就能优化为: for(int i=3;i<t/2;i+=2) { if(isprime(i)&&isprime(t-i)) output++; }#include<stdio.h>#include<math.h>#include<string.h>using namespace std;int isprime(int n){ int i; for(int i=2;i<=sqrt(n);i++) { if(n%i0) return 0; } return 1;}int main(){ int t; while(~scanf("%d",&t)) { if(t0)break; int output=0; for(int i=3;i<t/2;i+=2) { if(isprime(i)&&isprime(t-i)) output++; } printf("%d\n",output); }}11有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。源码#include <stdio.h>#include <stdlib.h>int main(){ int n; scanf("%d",&n); int start,direction; double way[51]={0}; way[2]=1; way[3]=2; for(int i=4;i<=50;i++) way[i]=way[i-1]+way[i-2]; for(int i=1;i<=n;i++){ scanf("%d%d",&start,&direction); printf("%.0f\n",way[direction-start+1]); } return 0;}12 龟兔赛跑解题思路:这题的思路应该不是很明显的,一开始想到的是以每一个点一个状态f[i]表示到达这一点的最短时间,但是就会发现加油站和普通的点的决策不相同,这处理起来有点麻烦,此外状态之间怎么转移也是个问题,这个方法具体为什么不行还是没有想清楚,先说一下题结的思路吧,题解中是把是否加油当作我们唯一的决策(一眼看上去好像并不正确,应为决策还包括是否使用电动车,但是仔细想一想电动车的使用应该是只要可以使用就使用,其实不应该构成决策),这样以来我们的状态就定义在加油站点就可以,这样不难退出状态转移方程#include #include #include using namespace std;int main(int argc, const char * argv[]) int l; while(scanf("%d",&l)!=EOF) { int n,c,t,vr,vt1,vt2,s[150]; double f[150]; memset(s,0,sizeof(s)); memset(f,0,sizeof(f)); scanf("%d%d%d",&n,&c,&t); scanf("%d%d%d",&vr,&vt1,&vt2); s[0]=0; s[n+1]=l; for(int i=1;i<=n;i++) scanf("%d",&s[i]); for(int i=1;i<=n+1;i++) { double minimum=999999999; for(int j=0;j<i;j++) { double time=0; int len=s[i]-s[j]; if(len<=c) time=(double)((double)len/(double)vt1); else { time=(double)((double)c/double(vt1))+(double)((double)(len-c)/(double)vt2); } if(j!=0) time+=t; if(f[j]+time<minimum) minimum=f[j]+time; } //cout<<minimum<<endl; f[i]=minimum; } //cout<<f[n+1]<<endl; double r=(double)l/(double) vr; if(f[n+1]-r>1e-8) cout<<“Good job,rabbit!”<<endl; else cout<<“What a pity rabbit!”<<endl; } return 0;}13 简要题意 每组数据的菜价就是数量乘上单价啊解题细节 在支付的时候采用四舍五入的方法把分头去掉源码#include #include using namespace std;int main(){ double sum=0; char a[50]; double x,y; while(cin>>a>>x>>y) { sum+=xy; } printf("%.1f\n",sum); return 0;}14简要题意一个整数,只知道前几位,不知道末二位,被另一个整数除尽了,求该数的末二位解题细节源码#include <stdio.h>#include <stdlib.h>int main(){ int i,a,b,s[100],k; while(~scanf("%d%d",&a,&b)&&(a||b)) { k=0; a=a100; for(i=0;i<100;i++) { if((a+i)%b0) { s[k]=i; k++; } } for(i=0;i<k-1;i++) { if(s[i]<10)printf(“0”); printf("%d “,s[i]); } if(s[k-1]<10)printf(“0”); printf(”%d\n",s[k-1]); } return 0;}15 简要题意:每行包含一个字符和一个整数n(0<n<41),不同的字符表示不同的花纹,整数n表示等腰三角形的高。显然其底边长为2n-1。如果遇到@字符,则表示所做出来的样板三角形已经够了。解题思路:这道题目很容易PE,主要要注意2个点,第一:每一行的最后一个字母后面没有空格(我最后一次PE就是没有注意到这一点的),这点很关键;第二,每个测试数据之间有一个空行,换句话说,就是最后一个测试数据后面没有空行。源码:#include using namespace std;int main(){ int n, flag=0; char c; while(cin>>c&&c!=’@’){ cin>>n; if(flag!=0) cout<<endl; for(int i=0; i<n-1; i++){ for(int j=n-i-2; j>=0; j–) cout<<" "; cout << c; if(i0) cout<<endl; else{ for(int k=i2-2; k>=0; k–) cout<<" "; cout << c << endl; } } for(int i=0; i<2n-1; i++) cout<<c; cout<<endl; flag = 1; //cout<<“exo me”<<endl; } return 0;}总结:通过这三天的学习,学到了更多的写代码的技巧,语法熟练的是必须的;熟练使用 STL 编程,面向对象思想不是一天两天就可以有的,需要不断的历练和实战才能培养出来的;面向对象在C++中的实现方式一定要熟(继承,派生,虚函数等);模板的实参演绎要搞清楚。多写代码,多调程序。培养错误的感知能力。学会挖掘,多思考。

猜你喜欢

转载自blog.csdn.net/qq_43641661/article/details/85843197