课程设计A实验报告数学3班付荣2018212805"/>
课程设计A实验报告数学3班付荣2018212805
- 题意: 当n在(x,y)范围内取整数值时,判定表达式n^2+n+41的值是否都为素数。
解题思路:将表达式的各个值储存在一个数组里面,再判断是否都为素数。
细节处理:当x和y同时为0时,不进行循环,应用break函数来实现。素数的判断这个细节是通过循环来实现的,并且应用了类于bool的判断(int a=0),来输出一个结果,并非多个结果。
判断素数方法 枚举当前2 到 本身的前一个 是否有能除尽的元素 若有 则不是素数 无 则是
可以优化到 根号下本身 因为 两个因子是重复的
源码:
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
int x, y, i, n, t, j;
int a[100];
while (cin >> x >> y)
{
if (x == 0 && y == 0)
break;
i = 0;
for (n = x; n <= y; n++)
{
a[i] = n*n + n + 41;
i++;
}
int s = 0;
t = y - x;
for (i = 0; i <= t; i++)
{
for (j = 2; j < a[i]; j++)
{
if (a[i] % j == 0)
{
s++;
break;
}
}
}
if (s == 0)
cout << "OK" << endl;
else
cout << "Sorry" << endl;
总结:素数是程序中经常考察的知识点,明白素数的定义,理清思路。
2.题意:输出集合A-集合B的差
解题思路:本题本质是枚举集合A的每一个元素,看集合B中是否有相同元素。如果有,就去掉,如果没有就保留输出。
细节处理:当集合A和集合B中元素个数为0时,应用break函数结束程序;判断完A中有无B的元素之后,将那个元素a[j]标记,最后输出时去掉或者判断最后是否为空集。
源码:
#include<iostream>
#include<algorithm>
using namespace std;
int a[110];
int b[110];
int main()
{
int n,m;
while(cin>>n>>m,!(n==0&m==0))
{
int k=0;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=m;i++)
cin>>b[i];
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(b[i]==a[j])
a[j]=0;
}
}
sort(a,a+n+1);
for(int i=1;i<=n;i++)
{
if(a[i]!=0)
{
cout<<a[i]<<" ";
k++;
}
}
if(k==0)
cout<<"NULL";
cout<<endl;
}
return 0;
}
感想:数学基本知识点很重要,有时候应用sort等函数会简单很多。
但是这个题不能应用sort 因为最后还要按照原来的顺序输出
本来想用sort 省时间
- 题意:有一头牛每年年初生一头小母牛并且小牛从第四个年头开始,每年年初也生一头小牛。第N年会有多少牛。
解题思路:这个题类似斐波那契数列(找规律题)。这个题的规律是:F(N)=F(N-1)+F(N-3)。因为每年的牛可以分为两批,第一批是上一年的牛,另一批是新生代的牛。上一年的牛是直接继承的,新生代的牛的来源是前前年的牛所生,所以加上前前年的数量。
细节处理:这个题前四年需要特判:a【1】=1;a【2】=2;a【3】=3;a【4】=4,从第五年开始循环跑数据。
源码:
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
int n, i;
long long a[100];
while(cin>>n)
{
if(n==0)
break;
a[1]=1;
a[2]=2;
a[3]=3;
a[4]=4;
for(i=5;i<60;i++)
{
a[i]=a[i-1]+a[i-3];
}
cout<<a[n]<<endl;
}
return 0;
}
感悟:斐波那契数列经常出现在C语言程序设计中,做这类题只需要找出an和其他项的关系即可(细心和耐心)
- 题意:有一个定义为从2开始的递增有序偶数并且长度为n的数列,现按照顺序每m个数求出一个平均值,如果最后不足m个,则以实际数量求平均值。
解题思路:m m个数相加,根据题目要求来做,没有更好的思路。
细节处理:应用一个数组来储存每一个平均值,最后输出
源码:
#include<iostream>
using namespace std;
int main()
{
int i,n,m;
int a[1000];
int b[1001];
while(cin>>m>>n)
{
int x = 0;
int s = 0;
int sum = 0;
for(int i = 1 ; i <= m;i++)
{
if (x == n)
{
x= 0;
b[s++] = sum/n;
sum = 0;
}
x++;
sum += i*2;
}
if(sum!=0)
b[s++] = sum/x;
for(int i= 0 ; i<s;i++)
{
if(i == s-1)
cout<<b[i]<<endl;
else
cout<<b[i]<<" ";
}
}
return 0;
}
感悟:很多题找不到快捷方法,只能根据题的意思来进行编程,有耐心和细心,一定可以做出来的。
- 题意:至少需要准备多少张人民币,才能在给每位老师发工资的时候都不用找零
解题思路:根据题意思考可知,即从最大的开始选,才能保证最后需要的人民币数最少。
细节处理:应用整除和求余来进行计算。
源码:
#include<iostream>
using namespace std;
int main()
{
int n,i,a[10000],b,c,d,e,f,g;
while(cin>>n)
{
if(n==0)
break;
for(i=0;i<n;i++)
cin>>a[i];
int sum=0;
for(i=0;i<n;i++)
{
b=a[i]/100;
c=(a[i]%100)/50;
d=(a[i]%100)%50/10;
e=(a[i]%100)%50%10/5;
f=(a[i]%100)%50%10%5/2;
g=(a[i]%100)%50%10%5%2/1;
sum=b+c+d+e+f+g+sum;
}
cout<<sum<<endl;
}
return 0;
}
6.题意:输入一个十进制数N,将它转换成R进制数输出。
解题思路:转化 R 进制的方法 :
用 十进制 为例
十进制是怎么区分每一位的
个位数 等于 N%10;
十位数 等于 减去个位数 然后 %100;
百位数 等于 减去百位数个位数 然后 %1000;
......
再说一个每个位数的数字代表了什么
十位数上的 数字 t
表示 个位数 t * 10 ;
也就是说 必须要有 t 个 10 才能变到 十位数的 t
对于每一个进制 也是同样的道理
比如现在有一个数
不管是什么进制(计算机中储存的所有数都是二进制的形式存储 然后补码的形式保存)
只要用了 / 号 绝对不会算错(都是补码运算)
给了你一个数 N
N%R 代表当前位数是多少
N/R 因为整形运算余数不保留 剩下的需要晋级 晋级的变为新的N
如果N等于0表明剩下的运算也结束了
更简单的思路是这样子想:
换成加法的形式:现在有 N个1要加起来变成一个R进制的 位数
第一位 逢R晋1,加着加着当前的位数变成一个小于 R的数
第二位 对上述晋升的位数 执行相同的操作即可
细节处理:R大于10时,需要考虑对应的数字规则(参考十六进制)
源码:
#include<iostream>
using namespace std;
char frdsz(int x)
{
if (x == 10)
return 'A';
if (x == 11)
return 'B';
if (x == 12)
return 'C';
if (x == 13)
return 'D';
if (x == 14)
return 'E';
if (x == 15)
return 'F';
}
int main()
{
int N, R;
int a[100];
int X;
bool shifoufushu;
while (cin >> N >> R)
{
X = 0;
shifoufushu = 0;
if (N < 0)
{
N = abs(N);
shifoufushu = 1;
}
while (1)
{
if (N <= 0)
break;
a[X] = N % R;
N = N / R;
X++;
}
if (shifoufushu)
{
cout << "-";
}
for (int i = X - 1; i >= 0; i--)
{
if (a[i] >= 10)
cout << frdsz(a[i]);
else
cout << a[i];
}
cout << endl;
}
}
感想:联系计算机进制转化是要明白是怎么样子转化的,要思考然后再实践。
7. 题意:计算A+B,A和B都是由3个整数组成,分别表示时分秒。
解题思路:从秒开始加,如果多于60就把多的那一部分加到分上面去;分相加同理。
细节处理:将时分秒利用数组巧妙的储存。
源码:
#include<iostream>
using namespace std;
int main()
{
int i,n,m;
int a[1000];
int b[1001];
int s[1001];
cin >> n;
while(n--)
{
for(int i= 0 ; i <3 ;i++)
cin>>a[i];
for(int j= 0 ; j < 3 ; j++)
cin>>b[j];
int jinwei=0;;
for(int j = 2 ; j>=0;j--)
{
s[j] =a[j]+b[j]+jinwei;
if(j != 0 && s[j]>=60)
{
jinwei = s[j]/60;
s[j] = s[j]%60;
}
else
{
jinwei = 0;
}
}
for(int i = 0;i<3;i++)
{
if(i == 2)
cout<<s[i]<<endl;
else
cout<<s[i]<<" ";
}
}
return 0;
}
感悟:实际问题实际分析,考虑实际再实践。
8.题意:有方程Ai = (Ai-1 + Ai+1)/2 - Ci ,给出A0, An+1, 和 C1, C2, .....Cn。计算A1 = ?
解题思路:推导出递归方程,然后进行编程计算。
推导过程 是举特例
从 A4 开始 能枚举出规律
细节处理:最后保留小数问题要记得保留,利用数组解决问题。
源码:
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
#include<iomanip>
using namespace std;
int main()
{
double a[3002];
double c[3002];
int n;
while(cin >> n)
{
cin >> a[0];
cin >> a[n+1];
for(int i= 0 ; i<n;i++)
cin >> c[i];
double a1 = a[0]*n + a[n+1];
for(int i = 1; i<=n;i++)
a1 -= 2.0*i*c[n-i];
cout<<fixed<<setprecision(2)<<a1/(n+1)<<endl;
}
}
感悟:关于数学方程题应在纸面上推出递推公式再进行编程。
9.题意:所有的短号都是是 6+手机号的后5位,给一个11位长的手机号码,找出对应的短号
解题思路:先输出一个6,在输出这个string的6—10位。
细节处理:字符串的处理
源码:
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
using namespace std;
int main()
{
int n;
cin >> n;
string t;
while(n--)
{
cin >> t;
cout<<"6";
for(int i=6; i<11;i++)
cout<<t[i];
cout<<endl;
}
}
感想:考虑输出格式规律使程序简化。
10.题意:求A^B的最后三位数表示的整数。
解题思路:每次只算最后三位数。比如:6789,第一次6789*6789,只算789*789就行,789*789的结果%1000再平方,一直这么下去。
源码:
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int n,m;
while(cin>>n>>m)
{
if( n== 0 && m == 0)
break;
int sum = 1;
while(m--)
{
sum = sum % 1000;
sum *= n;
//cout<< sum <<endl;
}
sum= sum % 1000;
cout<< sum <<endl;
}
}
11. 题意:判断给定的两个数是否是亲和数
解题思路:求出每一个数的真约数,再分别加起来,看是否是对方本身
源码:
#include<iostream>
using namespace std;
int main()
{
int A,B,M,i,a[10000],b[10000];
cin>>M;
while(M--)
{
cin>>A>>B;
int j=0,s=0;
for(i=1;i<A;i++)
{
if(A%i==0)
{
a[j]=i;
j++;
}
}
for(i=1;i<B;i++)
{
if(B%i==0)
{
b[s]=i;
s++;
}
}
int s1=0,s2=0;
for(i=0;i<=j-1;i++)
{
s1+=a[i];
}
for(i=0;i<=s-1;i++)
{
s2+=b[i];
}
if(A==s2&&B==s1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
12.题意:求买菜到底花了多少钱
思路:单价乘以斤数之后加起来
细节优化:由于是 四舍五入,所以最后加上一个 0.01输出,这是关键,因为计算机5舍6入,加上0.01就变成了四舍五入。
源码:
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
#include<iomanip>
using namespace std;
int main()
{
double a[3002];
double c[3002];
int n;
string t;
double sum = 0;
while(cin >> t)
{
double n;
double x;
cin >> n;
cin >> x;
sum += n*x;
}
cout<<fixed<<setprecision(1)<<sum+0.01<<endl;
}
13.题意:有一只蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。
解题思路:写出递推公式ai=ai-1+ai-2
源码:
#include<iostream>
using namespace std;
int main()
{
long long a[60];
a[1] = 1;
a[2] = 1;
for (int i = 3; i <= 55; i++)
{
a[i] = a[i - 1] + a[i - 2];
}
int n;
cin >> n;
while (n--)
{
int t;
int x;
cin >> t >> x;
int f = x - t;
cout << a[f+1] << endl;
}
}
- 2
题意 从两组数中找到最大的组合
思路
一开始错误的原因是任选一个女孩开始暴力枚举 根据女孩选男孩 最后tl 发现有很多相同的情况 比如 女孩 1 构成 1 2 女孩 2 构成 2 3 和 先女孩 2 3 女孩 1 2 是一样的效果 如果数据多样化的化 会有很多的重复情况 百度一下 如果 从头开始 只要任意一个女孩有分配的情况 就可以 比如 先枚举一个女孩 1 找到就返回
标记一下当前男孩指定的女孩为 1 (如果不标记 假设女孩3只能选男孩1 会造成 女孩1 占用了最优的位置 ) 枚举到下一个女孩
如果当前女孩 只能制定一个男孩 但是这个男孩又被别的女孩选了
那么这时 将这个男孩给这个女生 在标记一下这个男孩不能选 男孩一开始标记的女孩 再选一次 找到可以 找不到无所谓 反正这个题
是求个数 不是求匹配方案 这么for循环下了 祛除了很多重复情况
算法本义 匈牙利算法 二分图最大匹配算法
细节处理
主要是 b数组记录了 当前男孩选中的女孩 不停地递归 知道找到 当前最适合的方案 尽量让 这个方案由最优值
源码 :
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
#include<iomanip>
using namespace std;
int a[1000][1000];
bool boy[1000];
int ss[1000];
int K,M,N;
int minn = 0;
bool dfs(int x)
{
for(int i=1;i<=N;i++)
{
if (a[x][i]&& boy[i]==0)
{
boy[i] = 1;
if (ss[i]==0)
{
ss[i]=x;
return true;
}
else if(dfs(ss[i]))
{
ss[i]=x;
return true;
}
}
}
return false;
}
int main()
{
int n;
while(cin>>K)
{
if(K==0)
break;
memset(a,0,sizeof(a));
memset(boy,0,sizeof(boy));
memset(ss,0,sizeof(ss));
cin>>M>>N;
minn = 0;
for(int i = 0; i < K;i++)
{
int g ,b;
cin >> g >>b;
a[g][b] = 1;
}
for(int i = 1 ; i <= M; i++)
{
memset(boy,0,sizeof(boy));
if(dfs(i))
minn++;
}
cout <<minn<<endl;
}
}
15
题意 小乌龟的题 动态规划(百度一下)
解题思路 : 完全没有 从网上找了一篇博客 这是一个动态规划题目
动态规划 定义 局部最优解 解决不了全局最优的问题 这也是数学的一种学法
通常与贪心算法一起定义
贪心算法从 局部最优推出全局最优解
这个题 dp【i】指的是从 开始的位置 到 i 位置的最优情况
也就是小乌龟到i位置的最优解
枚举时候 先从 1 开始 由于是加满油的状态 所以 第一个加油站是一个固定的值 有初值情况
然后开始 从 2 开始 枚举前面是否加油 如果是0 代表从 头开始到现在
如果是 1 代表从 1 加油 走到 2
比较两个大小 得到到2 点的最优情况
然后从 3 开始 枚举 0 1 2 点是否加油 如果 0点加油 就是 0的最优情况 加上后续的
1点加油 就是 1的最优情况 加上后续的 因为到1的最优情况已经确定
所以 只需要考虑在1点如果不加油的情况来
下面推广到 n
因为 n以前的最优值都已经确定了
到 n只有 几种情况
N-1 -加满油 - n
- 2 加满油 - n
N-3 加满油到 n
是不是 考虑 当前位置是否加油 那不用管 因为 n-2 的最优解已经确定 所以 n-3 不加油的话 不影响全局 但是如果n-3加油的话
N-2 不是最优解 但是 n-1 可能是 这就说明了 局部最优 解决不了全局最优
但是从局部最优的情况 逐步地推到全局最优
细节处理 如果当前时开始位置的话不用加上 加油时间
源码
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std;
int main()
{
int L;
int N, C, T;
int VR, VT1, VT2;
double NS[1000];
double dp[1000];
while (cin >> L)
{
cin >> N >> C >> T;
cin >> VR >> VT1 >> VT2;
for (int i = 1; i <= N; i++)
{
cin >> NS[i];
}
double time;
int j;
NS[0] = 0;
NS[N + 1] = L;
dp[0] = 0;
for (int i = 1; i <= N+1; i++)
{
dp[i] = 1000000;
for ( j = 0; j < i; j++)
{
if ((NS[i] - NS[j]) > C)
{
time = 1.0*C / VT1 + 1.0*(NS[i] - NS[j] - C) / VT2;
}
else
{
time = 1.0*(NS[i] - NS[j]) / VT1;
}
if (j>0)
dp[i] = min(dp[i], dp[j] + time + T);
else
dp[i] = min(dp[i], dp[j] + time);
}
}
double timer = 1.0*L / VR;
if (timer > dp[N+1])
{
cout << "What a pity rabbit!" << endl;
}
- 题意: 当n在(x,y)范围内取整数值时,判定表达式n^2+n+41的值是否都为素数。
解题思路:将表达式的各个值储存在一个数组里面,再判断是否都为素数。
细节处理:当x和y同时为0时,不进行循环,应用break函数来实现。素数的判断这个细节是通过循环来实现的,并且应用了类于bool的判断(int a=0),来输出一个结果,并非多个结果。
判断素数方法 枚举当前2 到 本身的前一个 是否有能除尽的元素 若有 则不是素数 无 则是
可以优化到 根号下本身 因为 两个因子是重复的
源码:
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
int x, y, i, n, t, j;
int a[100];
while (cin >> x >> y)
{
if (x == 0 && y == 0)
break;
i = 0;
for (n = x; n <= y; n++)
{
a[i] = n*n + n + 41;
i++;
}
int s = 0;
t = y - x;
for (i = 0; i <= t; i++)
{
for (j = 2; j < a[i]; j++)
{
if (a[i] % j == 0)
{
s++;
break;
}
}
}
if (s == 0)
cout << "OK" << endl;
else
cout << "Sorry" << endl;
感想:素数的判断是C语言程序中常考的一个问题,应明白素数的定义,然后和程序结合起来。只输出一个最终结论时,应使用判断,防止多次输出。
- 题意:输出集合A-集合B的差
解题思路:本题本质是枚举集合A的每一个元素,看集合B中是否有相同元素。如果有,就去掉,如果没有就保留输出。
细节处理:当集合A和集合B中元素个数为0时,应用break函数结束程序;判断完A中有无B的元素之后,将那个元素a[j]标记,最后输出时去掉或者判断最后是否为空集。
源码:
#include<iostream>
#include<algorithm>
using namespace std;
int a[110];
int b[110];
int main()
{
int n,m;
while(cin>>n>>m,!(n==0&m==0))
{
int k=0;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=m;i++)
cin>>b[i];
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(b[i]==a[j])
a[j]=0;
}
}
sort(a,a+n+1);
for(int i=1;i<=n;i++)
{
if(a[i]!=0)
{
cout<<a[i]<<" ";
k++;
}
}
if(k==0)
cout<<"NULL";
cout<<endl;
}
return 0;
}
感想:数学基本知识点很重要,有时候应用sort等函数会简单很多。
但是这个题不能应用sort 因为最后还要按照原来的顺序输出
本来想用sort 省时间
- 题意:有一头牛每年年初生一头小母牛并且小牛从第四个年头开始,每年年初也生一头小牛。第N年会有多少牛。
解题思路:这个题类似斐波那契数列(找规律题)。这个题的规律是:F(N)=F(N-1)+F(N-3)。因为每年的牛可以分为两批,第一批是上一年的牛,另一批是新生代的牛。上一年的牛是直接继承的,新生代的牛的来源是前前年的牛所生,所以加上前前年的数量。
细节处理:这个题前四年需要特判:a【1】=1;a【2】=2;a【3】=3;a【4】=4,从第五年开始循环跑数据。
源码:
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
int n, i;
long long a[100];
while(cin>>n)
{
if(n==0)
break;
a[1]=1;
a[2]=2;
a[3]=3;
a[4]=4;
for(i=5;i<60;i++)
{
a[i]=a[i-1]+a[i-3];
}
cout<<a[n]<<endl;
}
return 0;
}
感悟:斐波那契数列经常出现在C语言程序设计中,做这类题只需要找出an和其他项的关系即可(细心和耐心)
- 题意:有一个定义为从2开始的递增有序偶数并且长度为n的数列,现按照顺序每m个数求出一个平均值,如果最后不足m个,则以实际数量求平均值。
解题思路:m m个数相加,根据题目要求来做,没有更好的思路。
细节处理:应用一个数组来储存每一个平均值,最后输出
源码:
#include<iostream>
using namespace std;
int main()
{
int i,n,m;
int a[1000];
int b[1001];
while(cin>>m>>n)
{
int x = 0;
int s = 0;
int sum = 0;
for(int i = 1 ; i <= m;i++)
{
if (x == n)
{
x= 0;
b[s++] = sum/n;
sum = 0;
}
x++;
sum += i*2;
}
if(sum!=0)
b[s++] = sum/x;
for(int i= 0 ; i<s;i++)
{
if(i == s-1)
cout<<b[i]<<endl;
else
cout<<b[i]<<" ";
}
}
return 0;
}
感悟:很多题找不到快捷方法,只能根据题的意思来进行编程,有耐心和细心,一定可以做出来的。
- 题意:至少需要准备多少张人民币,才能在给每位老师发工资的时候都不用找零
解题思路:根据题意思考可知,即从最大的开始选,才能保证最后需要的人民币数最少。
细节处理:应用整除和求余来进行计算。
源码:
#include<iostream>
using namespace std;
int main()
{
int n,i,a[10000],b,c,d,e,f,g;
while(cin>>n)
{
if(n==0)
break;
for(i=0;i<n;i++)
cin>>a[i];
int sum=0;
for(i=0;i<n;i++)
{
b=a[i]/100;
c=(a[i]%100)/50;
d=(a[i]%100)%50/10;
e=(a[i]%100)%50%10/5;
f=(a[i]%100)%50%10%5/2;
g=(a[i]%100)%50%10%5%2/1;
sum=b+c+d+e+f+g+sum;
}
cout<<sum<<endl;
}
return 0;
}
6.题意:输入一个十进制数N,将它转换成R进制数输出。
解题思路:转化 R 进制的方法 :
用 十进制 为例
十进制是怎么区分每一位的
个位数 等于 N%10;
十位数 等于 减去个位数 然后 %100;
百位数 等于 减去百位数个位数 然后 %1000;
......
再说一个每个位数的数字代表了什么
十位数上的 数字 t
表示 个位数 t * 10 ;
也就是说 必须要有 t 个 10 才能变到 十位数的 t
对于每一个进制 也是同样的道理
比如现在有一个数
不管是什么进制(计算机中储存的所有数都是二进制的形式存储 然后补码的形式保存)
只要用了 / 号 绝对不会算错(都是补码运算)
给了你一个数 N
N%R 代表当前位数是多少
N/R 因为整形运算余数不保留 剩下的需要晋级 晋级的变为新的N
如果N等于0表明剩下的运算也结束了
更简单的思路是这样子想:
换成加法的形式:现在有 N个1要加起来变成一个R进制的 位数
第一位 逢R晋1,加着加着当前的位数变成一个小于 R的数
第二位 对上述晋升的位数 执行相同的操作即可
细节处理:R大于10时,需要考虑对应的数字规则(参考十六进制)
源码:
#include<iostream>
using namespace std;
char frdsz(int x)
{
if (x == 10)
return 'A';
if (x == 11)
return 'B';
if (x == 12)
return 'C';
if (x == 13)
return 'D';
if (x == 14)
return 'E';
if (x == 15)
return 'F';
}
int main()
{
int N, R;
int a[100];
int X;
bool shifoufushu;
while (cin >> N >> R)
{
X = 0;
shifoufushu = 0;
if (N < 0)
{
N = abs(N);
shifoufushu = 1;
}
while (1)
{
if (N <= 0)
break;
a[X] = N % R;
N = N / R;
X++;
}
if (shifoufushu)
{
cout << "-";
}
for (int i = X - 1; i >= 0; i--)
{
if (a[i] >= 10)
cout << frdsz(a[i]);
else
cout << a[i];
}
cout << endl;
}
}
感想:联系计算机进制转化是要明白是怎么样子转化的,要思考然后再实践。
7. 题意:计算A+B,A和B都是由3个整数组成,分别表示时分秒。
解题思路:从秒开始加,如果多于60就把多的那一部分加到分上面去;分相加同理。
细节处理:将时分秒利用数组巧妙的储存。
源码:
#include<iostream>
using namespace std;
int main()
{
int i,n,m;
int a[1000];
int b[1001];
int s[1001];
cin >> n;
while(n--)
{
for(int i= 0 ; i <3 ;i++)
cin>>a[i];
for(int j= 0 ; j < 3 ; j++)
cin>>b[j];
int jinwei=0;;
for(int j = 2 ; j>=0;j--)
{
s[j] =a[j]+b[j]+jinwei;
if(j != 0 && s[j]>=60)
{
jinwei = s[j]/60;
s[j] = s[j]%60;
}
else
{
jinwei = 0;
}
}
for(int i = 0;i<3;i++)
{
if(i == 2)
cout<<s[i]<<endl;
else
cout<<s[i]<<" ";
}
}
return 0;
}
感悟:实际问题实际分析,考虑实际再实践。
8.题意:有方程Ai = (Ai-1 + Ai+1)/2 - Ci ,给出A0, An+1, 和 C1, C2, .....Cn。计算A1 = ?
解题思路:推导出递归方程,然后进行编程计算。
推导过程 是举特例
从 A4 开始 能枚举出规律
细节处理:最后保留小数问题要记得保留,利用数组解决问题。
源码:
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
#include<iomanip>
using namespace std;
int main()
{
double a[3002];
double c[3002];
int n;
while(cin >> n)
{
cin >> a[0];
cin >> a[n+1];
for(int i= 0 ; i<n;i++)
cin >> c[i];
double a1 = a[0]*n + a[n+1];
for(int i = 1; i<=n;i++)
a1 -= 2.0*i*c[n-i];
cout<<fixed<<setprecision(2)<<a1/(n+1)<<endl;
}
}
感悟:关于数学方程题应在纸面上推出递推公式再进行编程。
9.题意:所有的短号都是是 6+手机号的后5位,给一个11位长的手机号码,找出对应的短号
解题思路:先输出一个6,在输出这个string的6—10位。
细节处理:字符串的处理
源码:
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
using namespace std;
int main()
{
int n;
cin >> n;
string t;
while(n--)
{
cin >> t;
cout<<"6";
for(int i=6; i<11;i++)
cout<<t[i];
cout<<endl;
}
}
感想:考虑输出格式规律使程序简化。
10.题意:求A^B的最后三位数表示的整数。
解题思路:每次只算最后三位数。比如:6789,第一次6789*6789,只算789*789就行,789*789的结果%1000再平方,一直这么下去。
源码:
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int n,m;
while(cin>>n>>m)
{
if( n== 0 && m == 0)
break;
int sum = 1;
while(m--)
{
sum = sum % 1000;
sum *= n;
//cout<< sum <<endl;
}
sum= sum % 1000;
cout<< sum <<endl;
}
}
11. 题意:判断给定的两个数是否是亲和数
解题思路:求出每一个数的真约数,再分别加起来,看是否是对方本身
源码:
#include<iostream>
using namespace std;
int main()
{
int A,B,M,i,a[10000],b[10000];
cin>>M;
while(M--)
{
cin>>A>>B;
int j=0,s=0;
for(i=1;i<A;i++)
{
if(A%i==0)
{
a[j]=i;
j++;
}
}
for(i=1;i<B;i++)
{
if(B%i==0)
{
b[s]=i;
s++;
}
}
int s1=0,s2=0;
for(i=0;i<=j-1;i++)
{
s1+=a[i];
}
for(i=0;i<=s-1;i++)
{
s2+=b[i];
}
if(A==s2&&B==s1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
12.题意:求买菜到底花了多少钱
思路:单价乘以斤数之后加起来
细节优化:由于是 四舍五入,所以最后加上一个 0.01输出,这是关键,因为计算机5舍6入,加上0.01就变成了四舍五入。
源码:
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
#include<iomanip>
using namespace std;
int main()
{
double a[3002];
double c[3002];
int n;
string t;
double sum = 0;
while(cin >> t)
{
double n;
double x;
cin >> n;
cin >> x;
sum += n*x;
}
cout<<fixed<<setprecision(1)<<sum+0.01<<endl;
}
13.题意:有一只蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。
解题思路:写出递推公式ai=ai-1+ai-2
源码:
#include<iostream>
using namespace std;
int main()
{
long long a[60];
a[1] = 1;
a[2] = 1;
for (int i = 3; i <= 55; i++)
{
a[i] = a[i - 1] + a[i - 2];
}
int n;
cin >> n;
while (n--)
{
int t;
int x;
cin >> t >> x;
int f = x - t;
cout << a[f+1] << endl;
}
}
- 2
题意 从两组数中找到最大的组合
思路
一开始错误的原因是任选一个女孩开始暴力枚举 根据女孩选男孩 最后tl 发现有很多相同的情况 比如 女孩 1 构成 1 2 女孩 2 构成 2 3 和 先女孩 2 3 女孩 1 2 是一样的效果 如果数据多样化的化 会有很多的重复情况 百度一下 如果 从头开始 只要任意一个女孩有分配的情况 就可以 比如 先枚举一个女孩 1 找到就返回
标记一下当前男孩指定的女孩为 1 (如果不标记 假设女孩3只能选男孩1 会造成 女孩1 占用了最优的位置 ) 枚举到下一个女孩
如果当前女孩 只能制定一个男孩 但是这个男孩又被别的女孩选了
那么这时 将这个男孩给这个女生 在标记一下这个男孩不能选 男孩一开始标记的女孩 再选一次 找到可以 找不到无所谓 反正这个题
是求个数 不是求匹配方案 这么for循环下了 祛除了很多重复情况
算法本义 匈牙利算法 二分图最大匹配算法
细节处理
主要是 b数组记录了 当前男孩选中的女孩 不停地递归 知道找到 当前最适合的方案 尽量让 这个方案由最优值
源码 :
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
#include<iomanip>
using namespace std;
int a[1000][1000];
bool boy[1000];
int ss[1000];
int K,M,N;
int minn = 0;
bool dfs(int x)
{
for(int i=1;i<=N;i++)
{
if (a[x][i]&& boy[i]==0)
{
boy[i] = 1;
if (ss[i]==0)
{
ss[i]=x;
return true;
}
else if(dfs(ss[i]))
{
ss[i]=x;
return true;
}
}
}
return false;
}
int main()
{
int n;
while(cin>>K)
{
if(K==0)
break;
memset(a,0,sizeof(a));
memset(boy,0,sizeof(boy));
memset(ss,0,sizeof(ss));
cin>>M>>N;
minn = 0;
for(int i = 0; i < K;i++)
{
int g ,b;
cin >> g >>b;
a[g][b] = 1;
}
for(int i = 1 ; i <= M; i++)
{
memset(boy,0,sizeof(boy));
if(dfs(i))
minn++;
}
cout <<minn<<endl;
}
}
15
题意 小乌龟的题 动态规划(百度一下)
解题思路 : 完全没有 从网上找了一篇博客 这是一个动态规划题目
动态规划 定义 局部最优解 解决不了全局最优的问题 这也是数学的一种学法
通常与贪心算法一起定义
贪心算法从 局部最优推出全局最优解
这个题 dp【i】指的是从 开始的位置 到 i 位置的最优情况
也就是小乌龟到i位置的最优解
枚举时候 先从 1 开始 由于是加满油的状态 所以 第一个加油站是一个固定的值 有初值情况
然后开始 从 2 开始 枚举前面是否加油 如果是0 代表从 头开始到现在
如果是 1 代表从 1 加油 走到 2
比较两个大小 得到到2 点的最优情况
然后从 3 开始 枚举 0 1 2 点是否加油 如果 0点加油 就是 0的最优情况 加上后续的
1点加油 就是 1的最优情况 加上后续的 因为到1的最优情况已经确定
所以 只需要考虑在1点如果不加油的情况来
下面推广到 n
因为 n以前的最优值都已经确定了
到 n只有 几种情况
N-1 -加满油 - n
- 2 加满油 - n
N-3 加满油到 n
是不是 考虑 当前位置是否加油 那不用管 因为 n-2 的最优解已经确定 所以 n-3 不加油的话 不影响全局 但是如果n-3加油的话
N-2 不是最优解 但是 n-1 可能是 这就说明了 局部最优 解决不了全局最优
但是从局部最优的情况 逐步地推到全局最优
细节处理 如果当前时开始位置的话不用加上 加油时间
源码
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std;
int main()
{
int L;
int N, C, T;
int VR, VT1, VT2;
double NS[1000];
double dp[1000];
while (cin >> L)
{
cin >> N >> C >> T;
cin >> VR >> VT1 >> VT2;
for (int i = 1; i <= N; i++)
{
cin >> NS[i];
}
double time;
int j;
NS[0] = 0;
NS[N + 1] = L;
dp[0] = 0;
for (int i = 1; i <= N+1; i++)
{
dp[i] = 1000000;
for ( j = 0; j < i; j++)
{
if ((NS[i] - NS[j]) > C)
{
time = 1.0*C / VT1 + 1.0*(NS[i] - NS[j] - C) / VT2;
}
else
{
time = 1.0*(NS[i] - NS[j]) / VT1;
}
if (j>0)
dp[i] = min(dp[i], dp[j] + time + T);
else
dp[i] = min(dp[i], dp[j] + time);
}
}
double timer = 1.0*L / VR;
if (timer > dp[N+1])
{
cout << "What a pity rabbit!" << endl;
}
else
{
cout << "Good job,rabbit!"<<endl;
}
}
}
else
{
cout << "Good job,rabbit!"<<endl;
}
}
}
总结与感想:素数的判断是C语言程序中常考的一个问题,应明白素数的定义,然后和程序结合起来。只输出一个最终结论时,应使用判断,防止多次输出。斐波那契数列等数学知识点很重要,先找出规律再编程会简单很多。写程序更多的还考验的是细心和耐心,读懂题意很重要。(其他感想在每个题后都有具体感想)
更多推荐
课程设计A实验报告数学3班付荣2018212805
发布评论