问题描述
一个射击运动员打靶,每轮射击最高得分10环。问连续10轮总分正好90环的可能性有多少种?
不考虑运动员的技术因素,即认为相邻两次射击是不相关的,且任何得分都是可能发生的。
问题分析
1、每轮得分共有11种情况,0-10
2、采用逆向分析,假设10轮射击已经完毕,每轮得分分别为score[9],score[8],...,score[0],
先考虑第10轮和前面9轮的递归关系
假设第10轮得分为i, 0<=i<=10
则前面9轮得分总和必须为90-i,,90-i=score[8]+...+score[0]
假设第9轮得分为j, 0<=j<=10
则前面8轮得分总和必须为90-i-j,,90-i-j=score[7]+...+score[0]
...
因此,递归关系用到的两个参数是“第N轮”和“第N轮打完应得的总分数”
代码实现
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using std::cout;
using std::endl;
unsigned int score[10] = {0};
unsigned int sum = 0;
void Output()//在满足条件时调用,察看每轮打靶分数
{
for (int i = 0;i < 10;++i)
cout << score[i] << " ";
cout <<endl;
sum++;
}
/* 利用排列组合,共有11的10次方种可能。
递归查找
*/
void Find_s(unsigned int round/*第N轮*/,unsigned int total/*第N轮打完应得分数*/)
{
if (total > (round+1)*10 || total < 0)//C语言0下标开始,所以round+1
{
//cout << "impossible caught. "<<endl;
return;
}
if (0==round)//回退到第一轮,成功找到
{
score[0] = total;
Output();
return;
}
for (int i = 0;i <=10;++i)
{
score[round] = i;
Find_s(round-1,total-i);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwStart = GetTickCount();
Find_s(9,90);
DWORD dwEnd =GetTickCount();
cout << "total possible " << sum << "running time" << (dwEnd-dwStart)<<endl;
return 0;
}
问题延伸
一个射击运动员打靶,每轮射击最高得分10环。问连续10轮总分不少于90环的可能性有多少种?
不考虑运动员的技术因素,即认为相邻两次射击是不相关的,且任何得分都是可能发生的。
问题分析
整个问题分析的过程相同,不同的是total的含义改变,应该是“第N轮打完应得分数的下限”
代码实现
void Find_s(unsigned int round/*第N轮*/,unsigned int total/*第N轮打完应得分数的下限*/)
{
...
if (0==round)//回退到第一轮,成功找到
{
for(unsigned int k = total;k <= 10;++k){
score[0] = k;
Output();
}
return;
}
...
}