算法设计文档格式.docx
《算法设计文档格式.docx》由会员分享,可在线阅读,更多相关《算法设计文档格式.docx(25页珍藏版)》请在冰豆网上搜索。
Inputnumber5=90
Inputnumber6=99
Inputnumber7=97
Inputnumber8=92
Inputnumber9=91
Inputnumber10=95
Canceledmaxscore:
99
Canceledminscore:
90
Averagescore:
92
*思考题
题目条件不变,但考虑同时对评委评分进行裁判,即在10个评委中找出最公平(即评分最接返平均分)和最不公平(即与平均分的差距最大)的评委,程序应该怎样实现?
二、逆序问题
1、输入一个五位整数,将它反向输出。
例如输入12345,输出应为54321。
2、4位反序数
设N是一个四位数,它的9倍恰好是其反序数,求N。
反序数就是将整数的数字倒过来形成的整数。
例如:
1234的反序数是4321。
*题目分析与算法设计
可设整数N的千、百、十、个位为i、j、k、l,其取值均为0~9,则满足关系式:
(i*103+j*102+10*k+l)*9=(l*103+k*102+10*j+i)
的i、j、k、l即构成N。
inti;
for(i=1002;
1111;
i++)/*穷举四位数可能的值*/
if(i%10*1000+i/10%10*100+i/100%10*10+i/1000==i*9)
/*判断反序数是否是原整数的9倍*/
Thenumbersatisfiedstatsconditionis:
%d\\n"
/*若是则输出*/
Thenumbersatisfiedstatesconditionis:
1089
三、穷举法
1、百钱百鸡问题
中国古代数学家张丘建在他的《算经》中提出了著名的“百钱买百鸡问题”:
鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一,百钱买百鸡,问翁、母、雏各几何?
设鸡翁、鸡母、鸡雏的个数分别为x,y,z,题意给定共100钱要买百鸡,若全买公鸡最多买20只,显然x的值在0~20之间;
同理,y的取值范围在0~33之间,可得到下面的不定方程:
5x+3y+z/3=100
x+y+z=100
所以此问题可归结为求这个不定方程的整数解。
由程序设计实现不定方程的求解与手工计算不同。
在分析确定方程中未知数变化范围的前提下,可通过对未知数可变范围的穷举,验证方程在什么情况下成立,从而得到相应的解。
intx,y,z,j=0;
Folleingarepossibleplanstobuy100fowlswith100Yuan.\\n"
);
for(x=0;
x<
=20;
x++)/*外层循环控制鸡翁数*/
for(y=0;
y<
=33;
y++)/*内层循环控制鸡母数y在0~33变化*/
z=100-x-y;
/*内外层循环控制下,鸡雏数z的值受x,y的值的制约*/
if(z%3==0&
&
5*x+3*y+z/3==100)
/*验证取z值的合理性及得到一组解的合理性*/
%2d:
cock=%2dhen=%2dchicken=%2d\\n"
++j,x,y,z);
Follwingarepossibleplanstobuy100fowlswith100Yuan.
1:
cock=0hen=25chicken=75
2:
cock=4hen=18chicken=78
3:
cock=8hen=11chicken=81
4:
cock=12hen=4chicken=84
这类求解不定方程总理的实现,各层循环的控制变量直接与方程未知数有关,且采用对未知数的取值范上穷举和组合的方法来复盖可能得到的全部各组解。
能否根据题意更合理的设置循环控制条件来减少这种穷举和组合的次数,提高程序的执行效率,请读者考虑。
2、换分币
用一元人民币兑换成1分、2分和5分硬币,共有多少种不同的兑换方法。
根据题意设i,j,k分别为兑换的1分、2分、5分硬币所具有的钱数(分),则i,j,k的值应满足:
i+j+k=100
inti,j,k,count=1;
Therearefollwingsmallexchangeplansfor1Yuannote:
\\n"
for(i=0;
=100;
i++)/*i为1分硬币钱数,可取值0,1,2...,100*/
for(j=0;
j<
=100-i;
j+=2)/*j为2分硬币钱数,可取0值,2,4,...,100*/
for(k=0;
k<
=100-i-2*j;
k+=5)/*k为5分硬币钱数*/
if(i+j+k==100)
printf(count%4?
"
%d:
1*%d+2*%d+5*%d\\t"
:
1*%d+2*%d+5*%d\\n"
count++,i,j/2,k/5);
3、马克思手稿中的数学题
马克思手稿中有一道趣味数学问题:
有30个人,其中有男人、女人和小孩,在一家饭馆吃饭花了50先令;
每个男人花3先令,每个女人花2先令,每个小孩花1先令;
问男人、女人和小孩各有几人?
设x,y,z分别代表男人、女人和小孩。
按题目的要求,可得到下面的方程:
x+y+z=30
(1)
3x+2y+z=50
(2)
用方程程序求此不定方程的非负整数解,可先通过
(2)-
(1)式得:
2x+y=20(3)
由(3)式可知,x变化范围是0~10
intx,y,z,count=0;
MenWomenChildren\\n"
........................................\\n"
x++)
y=20-2*x;
/*x定值据(3)式求y*/
z=30-x-y;
/*由
(1)式求z*/
if(3*x+2*y+z==50)/*当前得到的一组解是否满足式
(2)*/
%2d:
%d%d%d\\n"
++count,x,y,z);
}}
4、借书方案知多少
小明有五本新书,要借给A,B,C三位小朋友,若每人每次只能借一本,则可以有多少种不同的借法?
*问题分析与算法设计
本问题实际上是一个排列问题,即求从5个中取3个进行排列的方法的总数。
首先对五本书从1至5进行编号,然后使用穷举的方法。
假设三个人分别借这五本书中的一本,当三个人所借的书的编号都不相同时,就是满足题意的一种借阅方法。
inta,b,c,count=0;
TherearediffrentmethodsforXMtodistributebooksto3readers:
for(a=1;
a<
=5;
a++)/*穷举第一个人借5本书中的1本的全部情况*/
for(b=1;
b<
b++)/*穷举第二个人借5本书中的一本的全部情况*/
for(c=1;
a!
=b&
c<
c++)/*当前两个人借不同的书时,穷举第三个人借5本书
中的1本的全部情况*/
if(c!
=a&
c!
=b)/*判断第三人与前两个人借的书是否不同*/
printf(count%8?
%d,%d,%d"
%d,%d,%d\\n"
++count,a,b,c);
/*打印可能的借阅方法*/
TherearediffrentmethodsforXMtodistributebooksto3readers:
1,2,32:
1,2,43:
1,2,54:
1,3,25:
1,3,4
6:
1,3,57:
1,4,28:
1,4,39:
1,4,510:
1,5,2
11:
1,5,312:
1,5,413:
2,1,314:
2,1,415:
2,1,5
16:
2,3,117:
2,3,418:
2,3,519:
2,4,120:
2,4,3
21:
2,4,522:
2,5,123:
2,5,324:
2,5,425:
3,1,2
26:
3,1,427:
3,1,528:
3,2,129:
3,2,430:
3,2,5
31:
3,4,132:
3,4,233:
3,4,534:
3,5,135:
3,5,2
36:
3,5,437:
4,1,238:
4,1,339:
4,1,540:
4,2,1
41:
4,2,342:
4,2,543:
4,3,144:
4,3,245:
4,3,5
46:
4,5,147:
4,5,248:
4,5,349:
5,1,250:
5,1,3
51:
5,1,452:
5,2,153:
5,2,354:
5,2,455:
5,3,1
56:
5,3,257:
5,3,458:
5,4,159:
5,4,260:
5,4,3
5、邮票组合
某人有四张3分的邮票和三张5分的邮票,用这些邮票中的一张或若干张可以得到多少种不同的邮资?
*问题分析与算法设计
将问题进行数学分析,不同张数和面值的邮票组成的邮资可用下列公式计算:
S=3*i+5*j
其中i为3分邮柰的张数,j为5分的张数
按题目的要求,3分的邮票可以取0、1、2、3、4张,5分的邮票可以取0、1、2、3张。
采用穷举方法进行组合,可以求出这些不同面值不同张数的邮标组合后的邮资。
*程序与程序注释
inta[27];
inti,j,k,s,n=0;
=4;
i++)/*i:
取三分邮票的张数*/
=3;
j++)/*j:
取5分邮票的张数*/
s=i*3+j*5;
/*计算组成的邮票面值*/
a[k];
k++)/*查找是否有相同的邮资*/
if(s==a[k])break;
if(!
a[k]&
s)/*没有找到相同的邮资则满足要求存入数组*/
a[k]=s;
n++;
%dkinds:
n);
k++)
%d"
a[k]);
19kinds:
510153813186111621914192412172227
四、约瑟夫问题
这是17世纪的法国数学家加斯帕在《数目的游戏问题》中讲的一个故事:
15个教徒和15个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:
30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。
问怎样排法,才能使每次投入大海的都是非教徒。
题目中30个人围成一圈,因而启发我们用一个循环的链来表示。
可以使用结构数组来构成一个循环链。
结构中有两个成员,其一为指向下一个人的指针,以构成环形的链;
其二为该人是否被扔下海的标记,为1表示还在船上。
从第一个人开始对还未扔下海的人进行计数,每数到9时,将结构中的标记改为0,表示该人已被扔下海了。
这样循环计数直到有15个人被扔下海为止。
structnode
intnextp;
/*指向下一个人的指针(下一个人的数组下标)*/
intno_out;
/*是否被扔下海的标记。
1:
没有被扔下海。
0:
已被扔下海*/
}link[31];
/*30个人,0号元素没有使用*/
inti,j,k;
Theoriginalcircleis(+:
pagendom,@:
christian):
=30;
i++)/*初始化结构数组*/
link.nextp=i+1;
/*指针指向下一个人(数组元素下标)*/
link.no_out=1;
/*标志置为1,表示人都在船上*/
link[30].nextp=1;
/*第30个人的指针指向第一个人以构成环*/
j=30;
/*j:
指向已经处理完毕的数组元素,从link指向的人开始计数*/
15;
已扔下海的人数计数器*/
;
)/*k:
决定哪个人被扔下海的计数器*/
if(k<
15)
j=link[j].nextp;
/*修改指针,取下一个人*/
k+=link[j].no_out;
/*进行计数。
因已扔下海的人计标记为0*/
elsebreak;
/*计数到15则停止计数*/
link[j].no_out=0;
/*将标记置0,表示该人已被扔下海*/
i++)/*输出结果*/
%c"
link.no_out?
\'
@\'
\'
+\'
/*+:
被扔下海,@:
在船上*/
Theoriginalcircleis(+:
pagandom,@:
+++@@+@+@@@+@+++@@+@@@+++@+@@+
(+"
表示被扔下海的非教徒@:
留在船上活命的教徒)
有N个小孩围成一圈并依次编号,教师指定从第M个小孩开始报数,报到第S个小孩即令其出列。
然后从下一个孩子继续报数,数到第S个小孩又令其出列,如此直到所有的孩子都出列。
求小孩出列的先后顺序。
五、古典问题:
1、有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总对数为多少?
程序分析:
兔子的规律为数列1,1,2,3,5,8,13,21....
问题可以抽象成下列数学公式:
Un=Un-1+Un-2
其中:
n是项数(n>
=3)。
它就是著名的菲波那奇数列,该数列的前几为:
1,1,2,3,5,8,13,21...
菲波那奇数列在程序中可以用多种方法进行处理。
按照其通项递推公式利用最基本的循环控制就可以实现题目的要求。
publicclassexp2{
publicstaticvoidmain(Stringargs[]){
inti=0;
for(i=1;
System.out.println(f(i));
}
publicstaticintf(intx) {
if(x==1||x==2) return1;
else returnf(x-1)+f(x-2);
}
2、求n!
(一般循环方法和递归求法)
n!
=n*(n-1)!
=n*(n-1)*(n-2)!
=…..=n*(n-1)*(n-2)*…..*1
floatfac(intn)
floatf;
if(n<
0)printf("
n<
0,dataerror!
elseif(n==0)f=1;
elseif(n==1)f=1;
elsef=fac(n-1)*n;
return(f);
main()
intn;
floaty;
inputaintegernumber:
n);
y=fac(n);
%d!
=%15.0f"
n,y);
3、牛顿迭代法求根
(用迭代法求a的平方根,答案用x表示。
求平方根的迭代公式为:
xn+1=(1/2)(xn+(a/xn))
#include<
math.h>
main()
{floata,x0,x1;
Enterapositivenumber:
%f"
a);
x0=a/2;
x1=(x0+a/x0)/2;
do
{x0=x1;
while(fabs(x0-x1)>
=1e-5);
Thesquarerootof%5.2fis%8.5f\n"
a,x1);
六、排序问题
1、写一个函数,用“起泡法”对输入的10个字符按由小到大顺序排列。
#defineN10
chara[N],i;
voidsort(charp[]);
printf("
\nPleaseinput%dcharacters:
\n"
N);
gets(a);
while(strlen(a)!
=10)
{printf("
\nInputerror!
\nPleaseinputagain!
\nTheoriginalarrayis:
puts(a);
sort(a);
\nThesortedarrayis:
voidsort(charp[])
inti,j;
chartemp;
for(i=0;
i<
N-1;
i++)/*只需要比较N-1次*/
for(j=0;
j<
N-1-i;
j++)
if(p[j]>
p[j+1])
{temp=p[j];
p[j]=p[j+1];
p[j+1]=temp;
2、用选择法对10个整数排序。
inta[10],i,j,min,temp;
\nPleaseinput10numbers:
10;
scanf("
a[i]);
%5d"
a[i]);
i++)/*可改为i<
9,只需要比较9次*/
{min=i;
for(j=i+1;
j++)
if(a[min]>
a[j])min=j;
/*找到该趟的最小值*/
if(min!
=i)temp=a[min],a[min]=a[i],a[i]=temp;
/*将最小值与剩余记录中的首记录交换*/
\nTheresultarrayis:
}_
七、日期类型
1、给出年、月、日,计算某日是某年的第几天
intdays(intyear,intmonth,intday)
{intday_sum=0,i;
intday_tab[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
for(i=1;
month;
day_sum+=day_tab[i];
day_sum+=day;
if((year%4==0&
year%100!
=0)||(year%400==0))
if(month>
2)day_sum+=1;
returnday_sum;
{
intyear,month,day;
\nPleaseinputtoday'
sdate(YEAR,MONTH,DAY):
%d,%d,%d"
year,&
month,&
day);
\nTodayisthe%dthdayof%d!
\n"
days(year,month,day),year);
2、利用结构体变量自己编程解决万年历问题:
输入任意一个日期,求该日是星期几。
万年历问题:
现行的天文历法是根据天体运行的规律,取每年365.2425天。
这样每400年有365.2425*400天,如果以365天作为一年,每400年就少了0.2425*400=97天。
这97天要靠设置闰年(每年366天)来凑齐,所以每400年中应该设置97个闰年。
按下列方法可确定哪年是闰年:
1.年份的末尾数能被4整除的年份是闰年。
如1972的72,1976的76,1980的80都能够被4整除,所以这些年份是闰年
2.年份末2位如果是00,那么,该年份数能被400整除的数才是闰年,如1900不能被400整除,所以它虽能被4整除,也不是闰年。
如2000年能被400整除,所以该年是闰年。
由此导出的万年历计算公式:
S=(X-1)+(X-