/************************************************************************/
/*面试例题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秒
*/
/************************************************************************/