C. 圆的切分
运行时间限制: 1000 运行内存限制: 65536
作者: scsyuanbaoku 是否specialjudge: False
题目描述
在一个平面上有一个圆和n条直线,这些直线中每一条在圆内同其他直线相交,假设没有3条直线相交于一点,试问这些直线将圆分成多少区域。
输入:
只有一个整数n(0<=n<100)。
输出:
只有一个整数,为圆被n条直线分成的区域的块数。
还是想放上这个题,记得高中上数学课讲到这个时还是很懵的,另外,我是会用递推式的人
#include<stdio.h>
int f(int i)
{
if(i==0)return 1;
else return i+f(i-1);
}
int main()
{
//每与一条直线相交就会多一块,与轮廓相交多一块,第n条直线,多n块
int n;
scanf("%d",&n);
printf("%d\n",f(n));
return 0;
}
D. 韩信点兵
运行时间限制: 1000 运行内存限制: 65536
作者: scsyuanbaoku 是否specialjudge: False
题目描述
韩信有一队兵,他想知道一共有多少人,便让士兵排队报数。站5人一排,多出1人;站6人一排,多出5人站;7人一排,多出6人;站11人一排,多出10人。问韩信至少有多少兵?
输入:
为一个整数n(0<n<10000)。
输出:
一个不小于n的整数,为韩信可能拥有兵的数量的最小值。
说说这个韩信点兵,我小时候是真不聪明啊。那个时候听到这类的问题就不怎么明白,现在懂了。有个口诀,加同补(补数,除数减余数)加上补数就能得最小公倍数,减同余,减掉相同的余数就能得到最小公倍数。代码如下
#include<stdio.h>
int main()
{
int n,i,bing;
scanf("%d",&n);
for(i=1;;i++)
{
bing=6*7*11*i-1;
if(bing%5==1&&(n<=bing))//用满足6,7,11的数作为基础,等号很重要
{
printf("%d\n",bing);break;
}
}
return 0;
}
E. 实验4_15_进制转换2
运行时间限制: 1000 运行内存限制: 65536
作者: bupt_admin 是否specialjudge: False
题目描述
问题描述:
你的任务是实现带小数的二进制数到十进制数的转换。二进制字符序列以字符“#”结尾,如“1011.101#”。将二进制数“1011.101”转换为十进制数的过程如下:
(1101.101)2=123+0*22+121+1*20+12{-1}+0*2{-2}+12^{-3}=(11.625){10}(1101.101)
2
=1∗2
3
+0∗2
2
+1∗2
1
+1∗2
0
+1∗2
−1
+0∗2
−2
+1∗2
−3
=(11.625)
10
二进制字符序列中只可能存在“0”、 “1”、 “.”、 “#”四种字符,不会出现任何其他字符。为了提高结果的精度,建议使用double类型的变量存储结果。
输入与输出要求:
输入一个以“#”结尾的字符序列,代表待转换的二进制数。输出转换后的十进制数,如果二进制数有小数部分,则输出结果保留6位有效数字;如果二进制数没有小数部分,则输出结果中没有小数点和小数部分。
程序运行效果:
Sample 1:
11001.0110#↙
25.375000↙
Sample 2:
1101#↙
13↙
在这个题上遇到了许多困难:
1、数据存储问题。最终还是采用了字符数组,因为它能存储数字、小数点和井号
2、如何将拆开的位数分别乘以它应乘的2的次方。这里利用’.'与
'#'号的位置,用循环将最大的算出来,依次除以2.
3、字符ascii码与本值的关系。一开始直接用a[i]去乘,得到超级大的数,后来才发现数字应减48才得本值。
4、浮点数与整型的变换。这点没注意,以致得到的结果一直没加小数点后的值。
下面是AC代码
#include<stdio.h>
int main()
{
char a[32];
int i,xsd=0,jh,gs=1;
scanf("%s",&a);//输入存储问题
//找到小数点,井号
//printf("%s\n",a);
/*double a;
scanf("%lf",&a);//没读到井号
printf("%lf\n",a);*/
//char a[32];
for(i=0;;i++)
{
if(a[i]=='.')xsd=i;//对'.'与'#'号的位置存储
if(a[i]=='#')
{
jh=i;break;
}
}
//printf("%d %d\n",xsd,jh);
if(xsd==0)
{
for(i=jh-1;i>0;i--)//将最高位要乘地2的次方计算出来
{
gs*=2;
}
//printf("%d\n",gs);
int sum=0;
for(i=0;i<jh;i++)
{
sum+=(a[i]-48)*gs; //拿来做运算的是字符的ascii码,所以减48才是它的本值
gs/=2;
}
printf("%d\n",sum);
}
else
{
double sum=0,gs2=2;
for(i=xsd-1;i>0;i--)
{
gs*=2;
}
//printf("%d\n",gs);
for(i=0;i<xsd;i++)
{
//printf("%d\n",a[i]);
//printf("%d\n",a[i]*gs);
sum+=((a[i]-48)*gs);
gs/=2;
//printf("%.6f\n",sum);
}
for(i=xsd+1;i<jh;i++)
{
//printf("%d\n",a[i]);
sum+=((a[i]-48)/gs2);
gs2*=2;//在gs2是整型的情况下,此处不能乘2,应乘2.0以得到浮点数,不然,上式全部加的都是0,sum值无法改变 ;在gs2是浮点数的情况下,乘2可得浮点数
//printf("%.6f\n",sum);
}
printf("%.6f\n",sum);
}
return 0;
}
G. 三角形
运行时间限制: 1000 运行内存限制: 65536
作者: scsyuanbaoku 是否specialjudge: False
题目描述
有一根绳子的长度为n(3<=n<1000且为整数),将该绳子分成三段,每段的长度为正整数,输出由该三段绳子组成的三角形个数。
输入样例
3
输出样例
1
看到这个题简单朴素的想法是循环,先来个三重循环
#include<stdio.h>
int main()
{
int n,i,j,k,sum=0;
scanf("%d",&n);
for(i=1;i<=n/3;i++)//此处取n/3,因为下面j=i,k=i,之后再循环无意义
for(j=i;j<n;j++)//这样写之后出现的数字都是后一位不会小于前一位,保证了循环的不重复
for(k=j;k<n;k++)//如何让重复的结果消失? (见上)
{
if((i+j+k==n)&&(i+j>k)&&(i+k)>j&&(k+j)>i)
{
sum++;
//printf("%d %d %d\n",i,j,k);
}
}
printf("%d\n",sum);
return 0;
}
寻找更简单的算法如下
#include<stdio.h>
int main()
{
int n,i,j,sum=0;
scanf("%d",&n);
for(i=1;i<=n/3;i++)//此处取n/3,因为下面j=i,k=i,之后再循环无意义
for(j=i;j<n;j++)//这样写之后出现的数字都是后一位不会小于前一位,保证了循环的不重复
if(n-i-j>=j)//将i+j+k=n,与第三重循环融在一起。当n-i-j<j时情况与前重复
if((i+j)>(n-i-j)&&(i+n-i-j)>j&&(j+n-i-j)>i)
sum++;
printf("%d\n",sum);
return 0;
}
在开始下题之前先插入一个关于乘方运算的程序
#include<stdio.h>
#include<math.h>
int main()
{
int c;
scanf("%d",&c);
printf("%d\n",2^c);//机器看不懂乘方运算
double a = pow(2, 10); // a等于2的10次方
printf("%lf\n",a);
return 0;
}
输入c=0并没有得到2的0次方,下面这个才是正宗的乘方运算
I. 实验4_3_回文数
运行时间限制: 1000 运行内存限制: 65536
作者: bupt_admin 是否specialjudge: False
题目描述
问题描述:
回文是指正读和反读都一样的数或文本段。例如,12321、55555、45554、11611都是回文数。输入一个长度不超过10位的整数n,判断它是否是回文数。
输入与输出要求:
输入一个整数n,即待判断的数字。当n为回文数时输出“Yes”,否则输出“No”。
程序运行效果:
Sample 1:
12321↙
Yes↙
Sample 2:
126521↙
No↙
以下代码的思路为,将该数首位与末位摘出来逐一比较,如果相等,将首位与末位去掉,重新比较新的首位与末位
#include<stdio.h>
int main()
{
int n,chushu=1,t1,t2,weishu=1,i,j,pd=1;
scanf("%d",&n);
//取出位数
j=n/10;
t1=n;
t2=n;
if(j==0)//只有一位
{
printf("Yes\n");
return 0;
}
while(j!=0)
{
n/=10;
j=n/10;
chushu*=10;
weishu++;//引入位数限定循环范围
}
//printf("%d\n",weishu);
for(i=1;i<=weishu/2;i++)
{
//printf("%d %d\n",(t1/chushu)%10,t2%10);
if((t1/chushu)%10==t2%10)//用于获取首位与末位
{
chushu/=10;
t2/=10;
}
else
{
pd=0;printf("No\n");break;
}
}
//printf("Yes\n");这句不能放在这里
if(pd==1)printf("Yes\n");//需要加一个变量作为判断
return 0;
}
更简单的思路是,直接将整个数倒过来与原数比较,若相等,即为回文数。
#include<stdio.h>
int main()
{
int n,weishu,daoshu=0,cfs=1,t,t1;
scanf("%d",&n);
t=n/10;
t1=n;
while(t!=0)
{
cfs*=10;
t/=10;
}
while(n!=0)
{
weishu=n%10;//这里是尾数
daoshu+=weishu*cfs;
n/=10;
cfs/=10;
}
//printf("%d %d\n",daoshu,t1);
if(daoshu==t1)printf("Yes");
else printf("No");
return 0;
}
这个方法求颠倒的数还是复杂,体现在仍然用了一个循环专门来求出从尾数变成最高位需要乘的10的次方(以上两个都有)吸取他人做法之后,得到改良后的代码
#include<stdio.h>
int main()
{
int n,s,daoshu=0;
scanf("%d",&n);
s=n;
while(s>0){
daoshu=daoshu*10+s%10;
s/=10;
}
if(daoshu==n)printf("Yes");
else printf("No");
return 0;
}
一些关于随机数的验证
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i;
for(i=1;i<=20;i++)
{
printf("%10d",rand());
if(i%5==0)
printf("\n");
}
//printf("%d\n",1+rand()%6); 一次产生一个
//printf("%d\n",0xfffff);
return 0;
}
数字很大,产生限定范围内的随机数:从X到Y,有Y-X+1个数,所以要产生从X到Y的数,只需要这样写:
k=rand()%(Y-X+1)+X; 或k=X+rand()%(Y-X+1);
以下是完整代码
#include<stdio.h>
#include<stdlib.h>
#include<time.h>//以时钟做种子
int main()
{
int i,seed;
srand(time(NULL));
/*scanf("%d",&seed);//自己输入种子以控制随机数
srand(seed);*/
for(i=1;i<=20;i++)
{
printf("%10d",0+rand()%6);//1+rand()%x,产生1到x的随机数
if(i%5==0)
printf("\n");
}
//printf("%d\n",1+rand()%6); 一次产生一个
//printf("%d\n",0xfffff);
return 0;
}
H. 实验3_B_小学奥数题
运行时间限制: 1000 运行内存限制: 65536
作者: scshuanghai 是否specialjudge: False
题目描述
上小学四年级的小王同学虽然很笨,但他非常喜欢钻研奥数题。他遇到了这样的一个计算分数的问题:S(n)=1/3+3/5+5/7+…+n/(n+2),n为小于40的奇数。题目要求根据n来计算S(n)的值。他苦思冥想也没找出规律来解这道题,其实这道题目根本就没有规律,是老师用来难为不听话的学生用的。小王同学知道了实情后仍然不放弃去解这道题。当n值很大时,用纸笔计算非常费力,用计算器也很麻烦,有的计算器也不能计算分数。现在他只能求助你来编程帮他实现计算S(n)了,注意S(n)的计算结果应为分数形式。
输入与输出要求:
输入一个整数n,n的范围是1—40,且为奇数。输出S(n)的计算结果,如输出S(3)的结果:“14/15”。
程序运行效果:
Sample 1:
7↙
764/315
Sample 2:
21↙
2861599189/334639305
Sample 3:
39↙
116320091982737732/6845630929362225
看到这题样例的时候就应该想到,用int型会溢出,换类型的时候输入输出格式符也应该换。这题还用到了求最小公倍数。(1h10多分才写出来)
//注意S(n)的计算结果应为分数形式
#include<stdio.h>
long long fenmu=1;
void zxgbs(int i)//最小公倍数
{
//表示分母;寻找分母最小公倍数,参照之前的代码
//多个数的最小公倍数?循环迭代?
long long t,t1,t2,j;
t1=fenmu;t2=i;//t2寄存i值
if(t1<i)t=i,i=t1,t1=t;
j=t1%i;
if(j==0)fenmu=t1;
else
{
while(j!=0)//求上级最小公倍数与此级的最小公倍数
{
t1=i;i=j;j=t1%i;
}
fenmu=fenmu/i*t2;//此处t2应是未发生变化时的i
}
//printf("%d\n",fenmu);
}
int main()
{
int n,i;//分子只需乘对应分母到公倍数所乘的数
long long fenzi=0;
scanf("%d",&n);
//s(n);
for(i=3;i<=n+2;i+=2)
{
zxgbs(i);
}//接下来处理分子
for(i=3;i<=n+2;i+=2)
{
//printf("%d")
fenzi+=((fenmu/i)*(i-2));
//printf("%lld\n",fenzi);//分子溢出?
}
//printf("%d\n%d\n",fenzi,fenmu);
printf("%lld/%lld\n",fenzi,fenmu);
return 0;
}
F. 实验4_20_牛顿迭代法
运行时间限制: 1000 运行内存限制: 65536
作者: bupt_admin 是否specialjudge: False
题目描述
问题描述:
注意:建议浮点数用double存储,用float精度可能不够。
输入与输出要求:
输入四个正整数a、b、c、d,代表方程的系数。输出方程在1附近的一个实根,占一行。
程序运行效果:
Sample 1:
1 3 5 2↙
-0.546602↙
Sample 2:
12 34 25 30↙
-2.399306↙
我以为这题很难,把它留到了最后,然而,10多分钟(近二十分钟)就写完。难道这题的实质是把公式表达出来?另外,如何判断它与真实值更接近?
#include<stdio.h>
#include<math.h>
int main()
{
int a,b,c,d;
double xn=1,xn1;
scanf("%d%d%d%d",&a,&b,&c,&d);
//导数方程
while(1)
{
double daoshu=3*a*xn*xn+2*b*xn+c;
double hanshu=a*xn*xn*xn+b*xn*xn+c*xn+d;
xn1=xn-(hanshu/daoshu);
if(fabs(xn1-xn)<=1e-5)
{
printf("%.6lf",xn1);break;
}
else xn=xn1;
}
return 0;
}
可参考原创博主:马同学高等数学 如何通俗易懂地讲解牛顿迭代法?