2012程序设计竞赛基础实训82

更新时间:2023-10-18 04:16:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

2012程序设计竞赛基础实训82

39 台球碰撞

在平面直角坐标系下,台球桌是一个左下角在(0,0),右上角在(L,W)的矩形。有一个球心在(x,y),半径为R的圆形母球放在台球桌上(整个球都在台球桌内)。受撞击后,球沿极角为b的射线(即:x正半轴逆时针旋转到此射线的角度为b)以初速度v飞出。因球与桌面的磨擦,球作的加速度为a的匀减速率运动,每次碰到球桌边框时均发生完全弹性碰撞(反射角等于入射角)。

试求球停止时球心所在位置。

输入: l=180,w=120,x=35,y=40,r=5,b=30,v=27,a=6

原题:

在平面直角坐标系下,台球桌是一个左下角在(0,0),右上角在(L,W)的矩形。有一个球心在(x,y),半径为R的圆形母球放在台球桌上(整个球都在台球桌内)。受撞击后,球沿极角为a的射线(即:x正半轴逆时针旋转到此射线的角度为a)飞出,每次碰到球桌时均发生完全弹性碰撞(球的速率不变,反射角等于入射角)。

如果球的速率为v,s个时间单位之后球心在什么地方?

输入

输入文件最多包含25组测试数据,每个数据仅一行,包含8个正整数L,W,x,y,R,a,v,s(100<=L,W<=105, 1<=R<=5, R<=x<=L-R, R<=y<=W-R, 0<=a<360, 1<=v,s<=105),含义见题目描述。L=W=x=y=R=a=v=s=0表示输入结束,你的程序不应当处理这一行。

输出

对于每组数据,输出仅一行,包含两个实数x, y,表明球心坐标为(x,y)。x和y应四舍五入保留两位小数。

样例输入 样例输出 100 100 80 10 5 90 2 23 80.00 56.00 110 100 70 10 5 180 1 9999 71.00 10.00 0 0 0 0 0 0 0 0 设计要点:

(1) 确定球心区域

设球心座标为(x,y),则有球心矩形区域:x1≤x≤x2,y1≤y≤y2 其中:x1=r,x2=l-r; y1=r,y2=w-r

(2) 没撞击时球位置 设开始时球心位于(x0,y0),球沿极角为a的射线射出,球的速率为v,s个时间单位之后球心在(x,y):

x=x0+v*s*cos(a*3.14159/180) y=y0+v*s*sin(a*3.14159/180)

(3) 撞击轴对称

若球与右竖边(x2)撞击,撞击后横月座标为:x=2*x2-x 若球与上横边(y2)撞击,撞击后纵月座标为:y=2*y2-y

程序设计:

// 台球碰撞 #include #include void main() {

double l,w,r,a,v,s,x,y,x1,x2,y1,y2;

printf(\请确定球台边框(l,w): \ printf(\请确定球心开始位置(x,y): \ scanf(\

printf(\请确定球半径r: \ printf(\请确定射击角度a: \ printf(\请确定射击速度v: \ printf(\请确定时间s: \ x1=r;x2=l-r;y1=r;y2=w-r;

x=x+v*s*cos(a*3.1415926/180); y=y+v*s*sin(a*3.1415926/180);

while(xx2 || yy2) {if(x>x2) x=2*x2-x; if(xy2) y=2*y2-y; if(y

printf(\所求位置为:(%.2f,%.2f).\\n\ }

请确定球台边框(l,w): 130,110

请确定球心开始位置(x,y): 30,40 请确定球半径r: 5 请确定射击角度a: 30 请确定射击速度v: 20 请确定时间s: 20

所求位置为:(113.59,40.00).

引申:在平面直角坐标系下,台球桌是一个左下角在(0,0),右上角在(L,W)的矩形。有一个球心在(x,y),半径为r的圆形母球放在台球桌上(整个球都在台球桌内)。受撞击后,球沿极角为b的射线(即:与正半轴逆时针旋转到此射线的角度为b)以初速度v飞出。因球与桌面的磨擦,球作的加速度为a的匀减速率运动,每次碰到球桌边框时均发生完全弹性碰撞(反射角等于入射角)。

试求球停止时球心所在位置。

解:球作的初速度为v0,加速度为a的匀减速率运动,设t时刻球的速度为vt,则

vt=v0-a*t

停止时vt=0,则运行时间为:t=v0/a

球运行距离为s=v0*t-a*t*t/2=v0*v0/2/a // 台球碰撞 #include #include void main() {

double l,w,r,a,b,v,s,x,y,x1,x2,y1,y2;

printf(\请确定球台边框(l,w): \

printf(\请确定球心开始位置(x,y): \ printf(\请确定球半径r: \ printf(\请确定射击角度b: \ printf(\请确定射击初速度v: \ printf(\请确定匀减速的加速度a: \ x1=r;x2=l-r;y1=r;y2=w-r; s= v*v/2/a;

x=x+s*cos(b*3.1415926/180); y=y+s*sin(b*3.1415926/180);

while(xx2 || yy2) {if(x>x2) x=2*x2-x; if(xy2) y=2*y2-y; if(y

printf(\球停止时球心所求位置为:(%.2f,%.2f).\\n\ }

请确定球台边框(l,w): 180,120 请确定球心开始位置(x,y): 35,40 请确定球半径r: 5 请确定射击角度b: 30 请确定射击初速度v: 27 请确定匀减速的加速度a: 6

球停止时球心所求位置为:(87.61,70.37).

40 守形数

若正整数n是它平方数的尾部,则称n为守形数,又称同构数。

例如,6是其平方数36的尾部,?76是其平方数5776的尾部,6与76都是守形数。

试求出指定区间[x,y]内所有守形数。 测试数据:

(1) x=10,y=10000, 输出:

(2) x=10000,y=1000000,输出:

1. 常规求解 (1) 设计要点

对指定范围[x,y]内的每一个整数a(约定a>1),求出其平方数s; 计算a的位数w,同时计算b=10^w,a的平方s的尾部c=s%b; 比较a,c,若a=c则输出守形数。 (2) 程序实现

// 求[x,y]内的守形数 #include void main()

{long int a,b,c,k,s,x,y;

printf(\求区间[x,y]中的守形数.\ printf(\请输入整数x,y:\ scanf(\ for(a=x;a<=y;a++)

{ s=a*a; // 计算a的平方数s b=1;k=a; while(k>0)

{b=b*10;k=k/10;}

c=s%b; // c为a的平方数s的尾部 if(a==c)

printf(\

} }

(3) 程序运行结果

求区间[x,y]中的守形数.请输入整数x,y:10,10000

25^2=625 76^2=5776 376^2=141376 625^2=390625 9376^2=87909376 2. 探索n位守形数 (1) 求解要点

为了求更多位数的守形数,可应用守形数的性质:一个m位守形数的尾部m-1位数也是一个守形数。

道理很简单,a是一个m位数,a的平方数尾部的m-1位仅由a的尾部m-1位决定而与a的其他位无关。

实施易知一位守形数有三个:1,5,6。则二位守形数的个位数字只可能是1,5,6这三个数字。根据这一思路,我们可应用递推求出多位守形数。

(2) 程序设计

// 求n位守形数 #include void main()

{ int n,d,k,j,i,t,m,w,z,u,v,a[500],b[500],c[500]; printf(\ for(d=1;d<=9;d++) {for(k=1;k<=500;k++)

{a[k]=0;b[k]=0;c[k]=0;}

a[1]=d; // 给个位数赋值 for(k=2;k<=n;k++) {for(j=0;j<=9;j++) {a[k]=j;v=0;

for(i=1;i<=k;i++) c[i]=0; // 探索a(k) for(i=1;i<=k;i++)

{for(z=0,t=1;t<=k;t++) {u=a[i]*a[t]+z;z=u/10;

b[i+t-1]=u; // 计算平方 }

for(w=0,m=i;m<=k;m++) {u=c[m]+b[m]+w;

w=u/10;c[m]=u; }

}

for(i=1;i<=k;i++)

if(a[i]!=c[i]) v=1; if(v==0) break; } }

if(v==0 && a[n]!=0) // 输出n位守形数结果 {printf(\结尾的%d守形数: \ for(k=n;k>=1;k--)

printf(\

printf(\}

} }

(3) 程序运行示例

运行程序, 输入n=30,得30位守形数

5结尾的30守形数: 106619977392256259918212890625 6结尾的30守形数: 893380022607743740081787109376

41 奇数序列运算式

在由指定相连奇数组成的序列的每相邻两项中插入运算符号: 若相邻两项都是合数,则两项中插入“-”号;

若相邻两项一项合数一项素数,则两项中插入“+”号; 若相邻两项都是素数,则两项中插入乘号“*”号;

输入奇数b,c(b

例如b=31,c=45,完成运算式为: 31+33-35+37+39+41*43+45=1913 测试数据:

(1) b=3,c=51 (2) b=2011,c=2029

// 奇数序列运算式 #define N 30000 #include #include void main()

{int b,c,f,m,n,k,i,j,a[N]; long t,s;

printf(\请输入首尾奇数b,c(b

{ for(t=0,j=3;j<=sqrt(2*k+m);j+=2) if((2*k+m)%j==0) {t=1;break;}

if(t==0) a[k]=1; // 标记第k个奇数2k+m为素数 }

printf(\

for(i=2;i<=n;i++) // 完成表达式

{if(a[i-1]+a[i]==0) printf(\插入减号 if(a[i-1]+a[i]==1) printf(\插入加号 if(a[i-1]+a[i]==2) printf(\插入乘号 }

s=0; a[0]=1-a[1]; a[n+1]=0;

for(i=1;i<=n;i++) // 计算表达式结果 { t=2*i+m;f=i;

while(a[i]+a[i+1]==2)

{i++;t=t*(2*i+m);} // 相邻项均为素数时相乘

if(a[f-1]+a[f]==0) s=s-t; if(a[f-1]+a[f]==1) s=s+t; }

printf(\}

请输入首尾奇数b,c(b

请输入首尾奇数b,c(b

42 构建旋转方阵

把整数1,2,...,n2 从外层至中心按顺时针方向螺旋排列所成的n×n方阵,?称顺转n阶方阵;按逆时针方向螺旋排列所成的称逆转n阶方阵。

1 24 23 22 21 20 19 2 25 40 39 38 37 18 3 26 41 48 47 36 17 4 27 42 49 46 35 16 5 28 43 44 45 34 15 6 29 30 31 32 33 14 7 8 9 10 11 12 13

上图为逆转7阶方阵。

设计程序选择分别打印逆转10阶方阵与顺转15阶方阵。

(1) 设计要点

打印二种旋转方阵关键在于数组元素的赋值以及赋值与打印的巧妙结合。 对应方阵的n行n列设置二维数组a(n,n)。令m=int(n/2),当n为偶数时?,方阵共m圈。当n为奇数时,方阵除m圈外正中间还有一个数a(m+1,m+1)=n*n。

对于m圈,每圈有上下左右四条边。最外圈定义为第1圈,从外往内依次定义为第2圈,?.第i圈每边有n-2i+1个数。

为了实现旋转准确对各圈各边的每一个数组元素赋值,我们引入中间变量s,t:

s=n-2i+1

t=t+4s (t置初值0)

设置i(1─m)循环对第i圈操作,设置j(i─n-i)循环对第i圈的四条边的n-2i+1个元素操作。i,j二重循环可对方阵的每一元素赋值。

在顺时针转方阵中,具体赋值为:

上行为a(i,j)=t+1-i+j:其中+j体现往右元素值递增1;+t-i体现随圈数i增加数值增加值;而1为具体调整数。

右列为a(j,n+1-i)=t+s+1+j-i,即在a(i,j)的基础上增s。

下行为a(n+1-i,j+1)=t+3*s-j+i:其中-j体现往左元素值递增1;+t+i?体现随圈数i增加数值增加值;而3*s为具体调整数。

左列为a(j+1,i)=t+4*s-j+i,即在a(n+1-i,j+1)基础上增s。

在逆时针转方阵中,还是上述赋值,只是打印输出时把行列互换。这样处理是巧妙的,较为简便。

(2) 程序实现 // 旋转方阵

#include #include void main()

{int i,j,m,n,t,s,z,a[20][20]; printf(\输入方阵阶n:\ scanf(\

printf(\方阵有以下两种旋转方式:\\n\ printf(\逆时针转 2: 顺时针转\\n\

printf(\选择旋转方式代码: \ m=n/2;t=0;

a[m+1][m+1]=n*n;

for(i=1;i<=m;i++) // 按规律给a数组赋值 {s=n+1-2*i;

for(j=i;j<=n-i;j++) {a[i][j]=t+1-i+j;

a[j][n+1-i]=t+s+1+j-i; a[n+1-i][j+1]=t+3*s-j+i; a[j+1][i]=t+4*s-j+i; }

t=t+4*s; }

printf(\所求旋转方阵为:\ for(i=1;i<=n;i++) {printf(\

for(j=1;j<=n;j++) // 按座标输出方阵 if(z%2==0)

printf(\ else

printf(\ } }

(3) 程序运行示例与变通 输入方阵阶n:7

方阵有以下两种旋转方式: 1: 逆时针转 2: 顺时针转 选择旋转方式代码: 1 所求旋转方阵为:

1 24 23 22 21 20 19 2 25 40 39 38 37 18 3 26 41 48 47 36 17 4 27 42 49 46 35 16 5 28 43 44 45 34 15 6 29 30 31 32 33 14 7 8 9 10 11 12 13

输入方阵阶n:8

方阵有以下两种旋转方式: 1: 逆时针转 2: 顺时针转

选择旋转方式代码: 2 所求旋转方阵为:

1 2 3 4 5 6 7 8 28 29 30 31 32 33 34 9 27 48 49 50 51 52 35 10 26 47 60 61 62 53 36 11 25 46 59 64 63 54 37 12 24 45 58 57 56 55 38 13 23 44 43 42 41 40 39 14 22 21 20 19 18 17 16 15

程序变通:把程序中的输出量a[i][j] 改变为n*n-a[i][j]+1,可输出由内到外的旋转方阵。

43 n!精确计算

定义n!=1*2*3*?*n

输入正整数n(<=100),精确计算并输出n!(若大于10位时输出其高10位) 测试数据: n=30 n=100

设计要点:

设置s数组,s[1]为阶乘的个位数字,s[2]为阶乘的十位数字,类推。 模拟竖式乘法,要注意每次乘时需进位。

// 模拟竖式乘法求n!的精确值 #include void main()

{ int d,i,j,m,n,s[1000];

printf(\请输入整数n(n>2): \ scanf(\

for(j=1;j<=2*n;j++) s[j]=0; s[1]=1;

for(i=2;i<=n;i++)

{ m=0; // 乘i前进位数m清零 for(j=1;j<=2*n;j++)

{ s[j]=s[j]*i+m; // 从个位开始,第j位乘i m=s[j]/10; // 十位以上为进位数 s[j]=s[j]; // 个位数字存储到本位 } }

i=2*n;

本文来源:https://www.bwwdw.com/article/h6tf.html

Top