c语言经典例题.docx

上传人:b****5 文档编号:7273414 上传时间:2023-01-22 格式:DOCX 页数:33 大小:57.26KB
下载 相关 举报
c语言经典例题.docx_第1页
第1页 / 共33页
c语言经典例题.docx_第2页
第2页 / 共33页
c语言经典例题.docx_第3页
第3页 / 共33页
c语言经典例题.docx_第4页
第4页 / 共33页
c语言经典例题.docx_第5页
第5页 / 共33页
点击查看更多>>
下载资源
资源描述

c语言经典例题.docx

《c语言经典例题.docx》由会员分享,可在线阅读,更多相关《c语言经典例题.docx(33页珍藏版)》请在冰豆网上搜索。

c语言经典例题.docx

c语言经典例题

 

在一个8×8国际象棋盘上,有8个皇后,每个皇后占一格;要求皇后间不会出现相互“攻击”的现象,即不能有两个皇后处在同一行、同一列或同一对角线上。

问共有多少种不同的方法。

*问题分析与算法设计

这是一个古老的具有代表性的问题,用计算机求解时的算法也很多,这里仅介绍一种。

采用一维数组来进行处理。

数组的下标i表示棋盘上的第i列,a[i]的值表示皇后在第i列所放的位置。

如:

a[1]=5,表示在棋盘的第一例的第五行放一个皇后。

程序中首先假定a[1]=1,表示第一个皇后放在棋盘的第一列的第一行的位置上,然后试探第二列中皇后可能的位置,找到合适的位置后,再处理后续的各列,这样通过各列的反复试探,可以最终找出皇后的全部摆放方法。

程序采用回溯法,算法的细节参看程序。

*程序说明与注释

#include

#defineNUM8/*定义数组的大小*/

inta[NUM+1];

intmain()

{

inti,k,flag,not_finish=1,count=0;

i=1;/*正在处理的元素下标,表示前i-1个元素已符合要求,正在处理第i个元素*/

a[1]=1;/*为数组的第一个元素赋初值*/

printf("Thepossibleconfigurationof8queensare:

\n");

while(not_finish)/*not_finish=1:

处理尚未结束*/

{

while(not_finish&&i<=NUM)/*处理尚未结束且还没处理到第NUM个元素*/

{

for(flag=1,k=1;flag&&k

if(a[k]==a[i])flag=0;

for(k=1;flag&&k

if((a[i]==a[k]-(k-i))||(a[i]==a[k]+(k-i)))flag=0;

if(!

flag)/*若存在矛盾不满足要求,需要重新设置第i个元素*/

{

if(a[i]==a[i-1])/*若a[i]的值已经经过一圈追上a[i-1]的值*/

{

i--;/*退回一步,重新试探处理前一个元素*/

if(i>1&&a[i]==NUM)

a[i]=1;/*当a[i]为NUM时将a[i]的值置1*/

elseif(i==1&&a[i]==NUM)

not_finish=0;/*当第一位的值达到NUM时结束*/

elsea[i]++;/*将a[i]的值取下一个值*/

}

elseif(a[i]==NUM)a[i]=1;

elsea[i]++;/*将a[i]的值取下一个值*/

}

elseif(++i<=NUM)

if(a[i-1]==NUM)a[i]=1;/*若前一个元素的值为NUM则a[i]=1*/

elsea[i]=a[i-1]+1;/*否则元素的值为前一个元素的下一个值*/

}

if(not_finish)

{

++count;

printf((count-1)%3?

"[%2d]:

":

"\n[%2d]:

",count);

for(k=1;k<=NUM;k++)/*输出结果*/

printf("%d",a[k]);

if(a[NUM-1]

elsea[NUM-1]=1;

i=NUM-1;/*开始寻找下一个足条件的解*/

}

}

}

例如:

当n=4,m=8时,将得到如下5个数列:

51114211331132212222按照条件使前一个元素的值一定大于等于当前元素的值,不断地向前推就可以解决问题。

下面的程序允许用户选定M和N,输出满足条件的所有数列。

输入m和n(20>=m>=n>0)求出满足以下方程的正整数数列i1,i2,...,in,使得:

i1+i1+...+in=m,且i1>=i2...>=in。

例如:

当n=4,m=8时,将得到如下5个数列:

51114211331132212222

*问题分析与算法设计

可将原题抽象为:

将M分解为N个整数,且N个整数的和为M,i1>=i2>=...>=in。

分解整数的方法很低多,由于题目中有"i1>=i2>=.....>=in,提示我们可先确定最右边in元素的值为1,然后按照条件使前一个元素的值一定大于等于当前元素的值,不断地向前推就可以解决问题。

下面的程序允许用户选定M和N,输出满足条件的所有数列。

*程序说明与注释

#include

#defineNUM10/*允许分解的最大元素数量*/

inti[NUM];/*记录分解出的数值的数组*/

intmain()

{

intsum,n,total,k,flag,count=0;

printf("Pleaseenterrequriedterms(<=10):

");

scanf("%d",&n);

printf("theirsum:

");

scanf("%d",&total);

sum=0;/*当前从后向前k个元素的和*/

k=n;/*从后向前正在处理的元素下标*/

i[n]=1;/*将最后一个元素的值置为1作为初始值*/

printf("Therearefollowingpossibleseries:

\n");

while

(1)

{

if(sum+i[k]

if(k<=1)/*若正要处理的是第一个元素*/

{i[1]=total-sum;flag=1;}/*则计算第一个元素的并置标记*/

else{

sum+=i[k--];

i[k]=i[k+1];/*置第k位的值后k-1*/

continue;/*继续向前处理其它元素*/

}

elseif(sum+i[k]>total||k!

=1)/*若和已超过total或不是第一个元素*/

{sum-=i[++k];flag=0;}/*k向后回退一个元素*/

elseflag=1;/*sum+i[k]=total&&k=1则设置flag标记*/

if(flag)

{

printf("[%d]:

",++count);

for(flag=1;flag<=n;++flag)

printf("%d",i[flag]);

printf("\n");

}

if(++k>n)/*k向后回退一个元素后判断是否已退出最后一个元素*/

break;

sum-=i[k];

i[k]++;/*试验下一个分解*/

}

}

*运行结果

Pleaseenterrequriedterms(<=10):

4

theirsum:

8

Therearefollowingpossibleseries:

[1]:

5111

[2]:

4211

[3]:

3311

[4]:

3221

[5]:

2222

 

在选美大奖赛的半决胜赛现场,有一批选手参加比赛,比赛的规则是最后得分越高,名次越低。

当半决决赛结束时,要在现场按照选手的出场顺序宣布最后得分和最后名次,获得相同分数的选手具有相同的名次,名次连续编号,不用考虑同名次的选手人数。

在选美大奖赛的半决胜赛现场,有一批选手参加比赛,比赛的规则是最后得分越高,名次越低。

当半决决赛结束时,要在现场按照选手的出场顺序宣布最后得分和最后名次,获得相同分数的选手具有相同的名次,名次连续编号,不用考虑同名次的选手人数。

例如:

选手序号:

1,2,3,4,5,6,7

选手得分:

5,3,4,7,3,5,6

则输出名次为:

3,1,2,5,1,3,4

请编程帮助大奖赛组委会完成半决赛的评分和排名工作。

*问题分析与算法设计

问题用程序设计语言加以表达的话,即为:

将数组A中的整数从小到大进行连续编号,要求不改变数组中元素的顺序,且相同的整数要具有相同的编号。

普通的排序方法均要改变数组元素原来的顺序,显然不能满足要求。

为此,引入一个专门存放名次的数组,再采用通常的算法:

在尚未排出名次的元素中找出最小值,并对具有相同值的元素进行处理,重复这一过程,直到全部元素排好为止。

*程序说明与注释

#include

#defineNUM7/*定义要处理的人数*/

inta[NUM+1]={0,5,3,4,7,3,5,6};/*为简单直接定义选手的分数*/

intm[NUM+1],l[NUM+1];/*m:

已编名次的标记数组l:

记录同名次元素的下标*/

intmain()

{

inti,smallest,num,k,j;

num=1;/*名次*/

for(i=1;i<=NUM;i++)/*控制扫描整个数组,每次处理一个名次*/

if(m[i]==0)/*若尚未进行名次处理(即找到第一个尚未处理的元素)*/

{

smallest=a[i];/*取第一个未处理的元素作为当前的最小值*/

k=1;/*数组l的下标,同名次的人数*/

l[k]=i;/*记录分值为smallest的同名次元素的下标*/

for(j=i+1;j<=NUM;j++)/*从下一个元素开始对余下的元素进行处理*/

if(m[j]==0)/*若为尚未进行处理的元素*/

if(a[j]

{

smallest=a[j];/*则重新设置当覵最小值*/

k=0;/*重新设置同名次人数*/

l[++k]=j;/*重新记录同名次元素下标*/

}

elseif(a[j]==smallest)/*若与当前最低分相同*/

l[++k]=j;/*记录同名次的元素下标*/

for(j=1;j<=k;j++)/*对同名次的元素进行名次处理*/

m[l[j>=num;

num++;/*名次加1*/

i=0;/*控制重新开始,找下一个没排名次的元素*/

}

printf("Player-NoscoreRank\n");

for(j=1;j<=NUM;j++)/*控制输出*/

printf("%3d%4d%4d\n",j,a[j],m[j]);

}

*运行结果

Player-NoScoreRank

153

231

342

575

531

353

764

将大于0小于1000的阿拉伯数字转换为罗马数字。

题目中给出了阿拉伯数字与罗马数字的对应关系,题中的数字转换实际上就是查表翻译。

即将整数的百、十、个位依次从整数中分解出来,查找表中相应的行后输出对应的字符

题目中给出了阿拉伯数字与罗马数字的对应关系,题中的数字转换实际上就是查表翻译。

即将整数的百、十、个位依次从整数中分解出来,查找表中相应的行后输出对应的字符。

*程序与程序设计

#include

intmain()

{

staticchar*a[][10]={"","I","II","III","IV","V","VI","VII","VIII","IX"

"","X","XX","XXX","XL","L","LX","LXX","LXXX","XCC",

"","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"

};/*建立对照表*/

intn,t,i,m;

printf("Pleaseenternumber:

");

scanf("%d",&n);/*输入整数*/

printf("%d=",n);

for(m=0,i=1000;m<3;m++,i/=10)

{

t=(n%i)/(i/10);/*从高位向低位依次取各位的数字*/

printf("%s",a[2-m][t]);/*通过对照表翻译输出*/

}

printf("\n");

}

*运行结果

1.Pleaseenternumber:

863

863=DCCCLXIII

2.Pleaseenternumber:

256

256=CCLVI

3.Pleaseenternumber:

355

355=CCCLV

4.Pleaseenternumber:

522

522=DXXII

5.Pleaseenternumber:

15

15=XV

*思考题

输入正整数N,产生对应的英文数字符串并输出,例如:

1ONE2TWO3THREE

10TEN11ELEVEN

135ONEHUNDREDTHIRTYFIVE

 

从前有一对长寿兎子,它们每一个月生一对兎子,新生的小兎子两个月就长大了,在第二个月的月底开始生它们的下一代小兎子,这样一代一代生下去,求解兎子增长数量的数列。

问题可以抽象成著名的斐波那契数列,该数列的前几为:

1,1,2,3,5,8,13,21...

从前有一对长寿兎子,它们每一个月生一对兎子,新生的小兎子两个月就长大了,在第二个月的月底开始生它们的下一代小兎子,这样一代一代生下去,求解兎子增长数量的数列。

*问题分析与算法设计

问题可以抽象成下列数学公式:

Un=Un-1+Un-2

其中:

n是项数(n>=3)。

它就是著名的斐波那契数列,该数列的前几为:

1,1,2,3,5,8,13,21...

斐波那契数列在程序中可以用多种方法进行处理。

按照其通项递推公式利用最基本的循环控制就可以实现题目的要求。

*程序说明与注释

#include

intmain()

{

intn,i,un1,un2,un;

for(n=2;n<3;)

{

printf("Pleaseenterrequirednumberofgeneration:

");

scanf("%d",&n);

if(n<3)printf("\nEntererror!

\n");/*控制输入正确的N值*/

}

un=un2=1;

printf("Therepidincreaseofrabbitsinfirst%dgenerationisasfelow:

\n",n);

printf("l\tl\t");

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

{

un1=un2;

un2=un;

un=un1+un2;/*利用通项公式求解N项的值*/

printf(i%10?

"%d\t":

"%d\n",un);

}

printf("\n");

}

*运行结果

Pleaseenterrequirednumberofgeneration:

20

Therepidincreaseofrabbitsinfirst20generationisasfelow:

11235813213455

891442333776109871597258441816765

 

约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。

目的是将最左边杆上的盘全部移到右边的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。

这就是著名的汉诺塔问题。

约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。

目的是将最左边杆上的盘全部移到右边的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。

*问题分析与算法设计

这是一个著名的问题,几乎所有的教材上都有这个问题。

由于条件是一次只能移动一个盘,且不允许大盘放在小盘上面,所以64个盘的移动次数是:

18,446,744,073,709,551,615

这是一个天文数字,若每一微秒可能计算(并不输出)一次移动,那么也需要几乎一百万年。

我们仅能找出问题的解决方法并解决较小N值时的汉诺塔,但很难用计算机解决64层的汉诺塔。

分析问题,找出移动盘子的正确算法。

首先考虑a杆下面的盘子而非杆上最上面的盘子,于是任务变成了:

*将上面的63个盘子移到b杆上;

*将a杆上剩下的盘子移到c杆上;

*将b杆上的全部盘子移到c杆上。

将这个过程继续下去,就是要先完成移动63个盘子、62个盘子、61个盘子....的工作。

为了更清楚地描述算法,可以定义一个函数movedisc(n,a,b,c)。

该函数的功能是:

将N个盘子从A杆上借助C杆移动到B杆上。

这样移动N个盘子的工作就可以按照以下过程进行:

1)movedisc(n-1,a,c,b);

2)将一个盘子从a移动到b上;

3)movedisc(n-1,c,b,a);

重复以上过程,直到将全部的盘子移动到位时为止。

*程序说明与注释

#include

voidmovedisc(unsignedn,charfromneedle,chartoneedle,charusingneedle);

inti=0;

intmain()

{

unsignedn;

printf("pleaseenterthenumberofdisc:

");

scanf("%d",&n);/*输入N值*/

printf("\tneedle:

\ta\tb\tc\n");

movedisc(n,'a','c','b');/*从A上借助B将N个盘子移动到C上*/

printf("\tTotal:

%d\n",i);

}

voidmovedisc(unsignedn,charfromneedle,chartoneedle,charusingneedle)

{

if(n>0)

{

movedisc(n-1,fromneedle,usingneedle,toneedle);

/*从fromneedle上借助toneedle将N-1个盘子移动到usingneedle上*/

++i;

switch(fromneedle)/*将fromneedle上的一个盘子移到toneedle上*/

{

case'a':

switch(toneedle)

{

case'b':

printf("\t[%d]:

\t%2d.........>%2d\n",i,n,n);

break;

case'c':

printf("\t[%d]:

\t%2d...............>%2d\n",i,n,n);

break;

}

break;

case'b':

switch(toneedle)

{

case'a':

printf("\t[%d]:

\t%2d<...............>%2d\n",i,n,n);

break;

case'c':

printf("\t[%d]:

\t%2d........>%2d\n",i,n,n);

break;

}

break;

case'c':

switch(toneedle)

{

case'a':

printf("\t[%d]:

\t%2d<............%2d\n",i,n,n);

break;

case'b':

printf("\t[%d]:

\t%2d<........%2d\n",i,n,n);

break;

}

break;

}

movedisc(n-1,usingneedle,toneedle,fromneedle);

/*从usingneedle上借助fromneedle将N-1个盘子移动到toneedle上*/

}

}

 

99.超长正整数的加法

作者:

不详 来源:

互联网 酷勤网收集 2008-04-25

摘要

酷勤网

  我们采用一个带有表头结点的环形链来表示一个非负的超大整数,如果从低位开始为每个数字编号,则第一位到第四位、第五位到第八位...的每四位组成的数字,依次放在链表的第一个、第二个、...结点中,不足4位的最高位存放在链表的最后一个结点中,表头结点的值规定为-1。

请设计一个算法来完成两个超长正整数的加法。

*问题分析与算法设计

首先要设计一种数据结构来表示一个超长的正整数,然后才能够设计算法。

首先我们采用一个带有表头结点的环形链来表示一个非负的超大整数,如果从低位开始为每个数字编号,则第一位到第四位、第五位到第八位...的每四位组成的数字,依次放在链表的第一个、第二个、...结点中,不足4位的最高位存放在链表的最后一个结点中,表头结点的值规定为-1。

例如:

大整数“587890987654321”可用如下的带表头结点head的链表表示:

按照此数据结构,可以从两个表头结点开始,顺序依次对应相加,求出所需要的进位后代入下面的运算。

具体的实现算法请见程序中的注释。

*程序说明与注释

#include

#include

#defineHUNTHOU10000

typedefstructnode{intdata;

structnode*next;

}NODE;/*定义链表结构*/

NODE*insert_after(NODE*u,intnum);/*在u结点后插入一个新的NODE,其值为num*/

NODE*addint(NODE*p,NODE*q);/*完成加法操作返回指向*p+*q结果的指针*/

voidprintint(NODE*s);

NODE*inputint(void);

intmain()

{

NODE*s1,*s2,*s;

NODE*inputint(),*addint(),*insert_after();

printf("EnterS1=");

s1=inputint();/*输入被加数*/

printf("EnterS2=");

s2=inputint();/*输入加数*/

printf("S1=");printint(s1);putchar('\n');/*显示被加数*/

printf("S2=");printint(s2);putchar('\n');/*显示加数*/

s=addint(s1,s2);/*求和*/

printf("S1+S2=");printint(s);putchar('\n');/*输出结果*/

}

NODE*insert_after(NODE*u,intnum)

{

NODE*v;

v=(NODE*)malloc(sizeof(NODE));/*申请一个NODE*/

v->data=num;/*赋值*/

u->next=v;/*在u结点后插入一个NODE*/

returnv;

}

NODE*addint(NODE*p,NODE*q)/*完成加法操作返回指向*p+*q结果的指针*/

{

NODE*pp,*qq,*r,*s,*t;

inttotal,number,carry;

pp=p->next

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 理学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1