一个射击选手打靶 java_面试 例题1: 一个射击运动员打靶 --递归 非递归

/************************************************************************/

/*面试例题1:一个射击运动员打靶

靶一共有10环,连开10枪打中90环的可能性有多少种?请用递归算法编程实现。[中国某著名通信企业H面试题]

解析:靶上一共有10种可能——1环到10环,还有可能脱靶,那就是0环,加在一起共11种可能。

这是一道考循环和递归的面试题。

我们在这个程序中将利用递归的办法实现打靶所有可能的演示,并计算出结果。

读者会问,难道一定要使用递归?

当然不是。我们也可以连续用10个循环语句来表示程序,代码如下:

*/

/************************************************************************/

#include

#include

usingnamespacestd;

#include

intmain()

{

cout<

SYSTEMTIMEsys;

GetLocalTime( &sys);

printf("calling

quick\n");

printf("%4d/%02d/%02d

%02d:%02d:%02d.%03d星期%1d\n",sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute,sys.wSecond,sys.wMilliseconds,sys.wDayOfWeek);

intsum= 0;

for(inti1=0;i1<= 10;i1++)

{

for(inti2=0;i2<= 10;i2++)

{

for(inti3=0;i3<= 10;i3++)

{

for(inti4=0;i4<= 10;i4++)

{

for(inti5=0;i5<= 10;i5++)

{

for(inti6=0;i6<= 10;i6++)

{

for(inti7=0;i7<= 10;i7++)

{

for(inti8=0;i8<= 10;i8++)

{

for(inti9=0;i9<= 10;i9++)

{

for(inti10=0;i10<= 10;i10++)

{

if((i1+i2+i3+i4+i5+i6+i7+i8+i9+i10) == 90)

{

++sum;

}

}

}

}

}

}

}

}

}

}

}

cout<

SYSTEMTIMEsys2;

GetLocalTime( &sys2);

printf("%4d/%02d/%02d

%02d:%02d:%02d.%03d星期%1d\n",sys2.wYear,sys2.wMonth,sys2.wDay,sys2.wHour,sys2.wMinute,sys2.wSecond,sys2.wMilliseconds,sys2.wDayOfWeek);

cout<

return0;

}

/************************************************************************/

/*

开始打靶

calling quick

2012/07/26 16:34:55.546星期4

92378

2012/07/26 16:37:00.500星期4

结束打靶

Press any key to continue

可以看出:用时两分多钟,远超出递归算法的0.015秒的时间,

所以上面的循环程序虽然解决了问题,但时间复杂度和空间复杂度无疑是很高的。比较好的办法当然是采用递归的方式,代码如下

*/

/************************************************************************/

#include

usingnamespacestd;

#include

intsum;//统计满足条件的总个数

intstore[10];//记录每一枪的成绩

voidOutput()

{

//for(int i =

9; i>=0; --i)

//{

//cout<

";

//}

++sum;

//cout<

}

/************************************************************************/

/************************************************************************/

/*打靶问题思路:已知一个固定值,求满足这个固定值的条件,

如本题:已知一个固定值90环,经过10轮变化,每一轮在流程上都是上一轮的完全重复,每一轮的成绩是相互不影响的

唯一的不同就是总靶数在上一轮的基础上进行了增加,也就是说完全可以把它分为10个阶段,

这10个阶段由num的递归依次递减1来控制(也就是说这10个阶段的循环是隐形的,是通过递归来实现的),

而我们实际上要实现的就是一轮上的具体实现,以及边界结束条件的截取和判断

for (int i1=0; i1 <= 10; i1++)

{

for (int

i2=0; i2 <= 10; i2++)

{

...............

for

(int i10=0; i10 <= 10; i10++)

{

if

((i1+i2+i3+i4+i5+i6+i7+i8+i9+i10) == 90)

{

++sum;

}

}

.....................

}

}

完全可以用

for (int i10=0; i10 <= 10; i10++)

{

for (int

i9=0; i9 <= 10; i9++)

{

...............

for

(int i1=0; i1 <= 10; i1++)

{

if

((i1+i2+i3+i4+i5+i6+i7+i8+i9+i10) == 90)

{

++sum;

}

}

.....................

}

}

又因为阶段可以用递归来隐形实现,所以只需要一轮的实现,表现如下

for (int i10=0; i10 <= 10; i10++)

{

Cumput();//递归函数

}

然后把它完善:

Cumput(int num)//num控制轮次

{

边界条件

for (int i=0;

i <= 10; i++)//因为轮次是隐形实现的(即用递归代替for循环),就没有必要用for循环具体实现了,

//只需通过参数控制就行了

//只需要体现环数的情况就可以了,所以i就可以表示能打中的环数

{

Cumput(num-1);//递归函数

}

};

然后再加上每轮的剩余总环数的控制

Cumput(int score, int num)//控制轮次

{

边界条件

for (int i=0;

i <= 10; i++)

{

Cumput(score-i,num-1);//递归函数,就是假设这一轮打中了i环,那么剩余总环数还有score-i环,剩余轮次num-1次,

//把剩余的这些作为一个整体,递归去求,这本就是递归的思想

}

};

*/

/************************************************************************/

/************************************************************************/

voidCumput(intscore,intnum)

{

/************************************************************************/

/*如果总成绩超过了90环(也就是score

< 0)

或者出现这种情况,即便后面每枪都打10环也无法打够总环数90,

在这两种情况下就不用再打了,则退出递归

*/

/************************************************************************/

//(1)

if(score< 0 ||score> (num+1)*10 )//次数num为0~9

return;

//(2)

if(num== 0)//如果在满足条件(1)后,就必须打到最后一次,(因为在满足(1)的条件后,必须打10次,才能满足题意)

{

store[num] =score;//只要保证最后一回打靶打score这个分数,就满足90环的条件

Output();

return;

}

//(3)如果出现以上两种情况则执行递归

for(inti= 0;i<= 10;

++i)//这里的i表示假如这一回能打中的环数

{

//这里实际上是为了方便,把顺序倒了过来,store[9]是第1回打靶分数,store[8]是第2回,store[0]是第10回,

store[num] =i;

Cumput(score-i,num- 1);

}

}

intmain(intargc,char*argv[])

{

//freopen("output.txt",

"w", stdout);

cout<

SYSTEMTIMEsys;

GetLocalTime( &sys);

printf("calling

quick\n");

printf("%4d/%02d/%02d

%02d:%02d:%02d.%03d星期%1d\n\n",sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute,sys.wSecond,sys.wMilliseconds,sys.wDayOfWeek);

Cumput(90,

9);

cout<

SYSTEMTIMEsys2;

GetLocalTime( &sys2);

printf("%4d/%02d/%02d

%02d:%02d:%02d.%03d星期%1d\n",sys2.wYear,sys2.wMonth,sys2.wDay,sys2.wHour,sys2.wMinute,sys2.wSecond,sys2.wMilliseconds,sys2.wDayOfWeek);

cout<

return0;

}

/************************************************************************/

/*

开始打靶

calling quick

2012/07/26 16:40:27.328星期4

总数:92378

2012/07/26 16:40:27.343星期4

结束打靶

Press any key to continue

可以看出:用时0.015秒

*/

/************************************************************************/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值