递归计算战士打靶S次打了N环一共同拥有多少种可能的问题

问题描写叙述

一个战士打了10次靶。一共打了90环,问一共同拥有多少种可能,并输出这些可能的组合。

思路

首先。嵌套10层循环进行穷举是不可取的,一是由于速度太慢,二是假设改成打20次靶就完蛋了。

事实上这就是一个树的搜索问题。

1. 设第一次打了0环。那么第二次可能打0 ~ 10环这些可能

2. 以第一次打的0环为root,将第二次全部可能的环数都做为root的子结点

3. 反复1, 2步

这样就构成了一棵树。表示当第一次打了0环时全部的可能性。

我们要做的就是从上到下遍历这棵树。当经过的结点之和等于90时,即命中。

然后再将根结点值改成1,直到10。

那么问题来了,一棵树须要遍历多少种组合呢?设打靶次数为t, 那么全部的组合数 = 1+(11)t?1=1+(11)9 种。这个结果已经超过了4亿, 显然全部遍历一遍时间上是不能忍的。我们能够通过剪枝思想来去掉部分不必要的遍历,即推断一下即便以后全打10环时能不能满足90环的要求,假设不能则不须要继续递归了。

另一个问题,我们真的要手动创建一个树形数据结构来运行上面的过程吗?假设这样做理论上是没问题的,可是会消耗大量的内存。 事实上我们能够使用递归的方式来模拟树的遍历。

实现

定义方法

int shoot(int score, int left, int totalScores, Dequeue<Integer> path)

表示已经打了score环。还要打left枪,总环数为totalScores时全部的结果数。这里path是一个栈数据结构。用来记录递归调用的路径,从而记录了一次可能组合的各个环数。

完整代码例如以下:

public class Main {
    public static int SHOOT_TIMES = 10;

    public static void main(String[] args) {
        System.out.println(shoot(0, SHOOT_TIMES, 90, new LinkedList<>()));
    }

    /**
     * 返回打score环且仅仅能打left枪且总环数为TOTAL_SCORES的全部结果数
     * @param score
     * @param left
     * @param path
     * @return
     */
    public static int shoot(int score, int left, int totalScores, Deque<Integer> path) {
        int tot = 0;
        if (1 == left) {
            // 剪枝
            // 去掉明显不可能的结果
            // 即在最后一枪时计算距离90环还剩下的环数,
            // 假设环数大于10。则不可能打满
            int left_scores = totalScores - score;
            // 当剩下的环数在0 ~ 10之间时。表明这是一个可取的组合
            if (left_scores >= 0 && left_scores <= 10) {
                path.push(left_scores);
                printStack(path);
                path.pop();

                ++tot;
            }

            path.pop();
            return tot;
        }

        for (int i = 0 ; i <= 10 ; ++i) {
            // 剪枝.
            // 计算已经打了score环时还剩下多少环.
            // 假设即便剩下全打10环还打不满90环,则表示这不是一个可取的结果
            if (totalScores - (score + i) <= 10 * left) {
                path.push(i);
                tot += shoot(score + i, left - 1, totalScores, path);
            }
        }

        if (false == path.isEmpty()) {
            path.pop();
        }
        return tot;
    }

    /**
     * 打印出栈内的全部元素
     * @param list
     */
    private static void printStack(Deque<Integer> list) {
        int ix = 0;
        int LEN = list.size();
        for (Integer n : list) {
            if (ix == LEN - 1) {
                System.out.printf("%d\n", n);
                break;
            }
            System.out.printf("%d, ", n);

            ++ix;
        }
    }
}
时间: 2024-11-09 01:39:31

递归计算战士打靶S次打了N环一共同拥有多少种可能的问题的相关文章

递归计算战士打靶S次打了N环一共有多少种可能的问题

问题描述 一个战士打了10次靶,一共打了90环,问一共有多少种可能,并输出这些可能的组合. 思路 首先,嵌套10层循环进行穷举是不可取的,一是因为速度太慢,二是如果改成打20次靶就完蛋了. 其实这就是一个树的搜索问题. 1. 设第一次打了0环,那么第二次可能打0 ~ 10环这些可能 2. 以第一次打的0环为root,将第二次所有可能的环数都做为root的子结点 3. 重复1, 2步 这样就构成了一棵树,表示当第一次打了0环时所有的可能性.我们要做的就是从上到下遍历这棵树,当经过的结点之和等于90

递归解决战士打靶N坏一共有多少种可能的问题

问题描述 一个战士打了10次靶,一共打了90环,问一共有多少种可能,并输出这些可能的组合. 思路 首先,嵌套10层循环进行穷举是不可取的,一是因为速度太慢,二是如果改成打20次靶就完蛋了. 其实这就是一个树的搜索问题. 1. 设第一次打了0环,那么第二次可能打0 ~ 10环这些可能 2. 以第一次打的0环为root,将第二次所有可能的环数都做为root的子结点 3. 重复1, 2步 这样就构成了一棵树,表示当第一次打了0环时所有的可能性.我们要做的就是从上到下遍历这棵树,当经过的结点之和等于90

【算法】打靶问题求解

问题描述:打一枪可能的环数为0~10,求打10枪总环数为90的概率. 这是一道排列组合问题,可以用循环加递归的方法解决.比如,第一次可以打出0~10环,那么先固定第一次打的环数,然后加上剩下的九次打的环数,就得到总环数.而剩下九次的环数通过递归很容易求得.代码如下: #include <iostream> using namespace std; int cnt = 0; int target = 90; void Permutation(int *numbers, int index, in

打靶问题

/** 打靶问题:一个射击运动员打靶,靶一共有10环,连开10枪打中90环的可能性有多少? 思路:这道题的思路与字符串的组合很像,用递归解决. 一次射击有11种可能,命中1环至10环,或脱靶. */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <vector> using namespace std; //函数功能 : 求

hihoCoder_二分&#183;归并排序之逆序对

一.题目 题目1 : 二分·归并排序之逆序对 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在上一回.上上回以及上上上回里我们知道Nettle在玩<艦これ>.经过了一番苦战之后,Nettle又获得了的很多很多的船. 这一天Nettle在检查自己的舰队列表: 我们可以看到,船默认排序是以等级为参数.但实际上一个船的火力值和等级的关系并不大,所以会存在A船比B船等级高,但是A船火力却低于B船这样的情况.比如上图中77级的飞龙改二火力就小于55级的夕立改二. 现在Ne

巨人网络 征途3——《战国征途》之构想

(PS:本文章内容纯属为我个人之想,若有不妥之处欢迎砸砖指正,但请不要进行人身攻击.本文章開始写作日期,2010年12月初) 首先,我要对这篇本章的标题进行一个小小的提问:为什么标题上"征途3"三字之前一定要加上"巨人网络"一词呢,难道就由于巨人网络推出了<征途>和<征途2>就一定会再推出<征途3>而其它的网络游戏公司就不许推出<征途3>吗?但本人的解释是仅仅有巨人网络才最具有本人设想的大型网络游戏征途3--<战

一点基础知识

1.肉鸡:所谓“肉鸡”是一种很形象的比喻,比喻那些可以随意被我们控制的电脑,对方可以是WINDOWS系统,也可以是UNIX/LINUX系统,可以是普通的个人电脑,也可以是大型的服务器,我们可以象操作自己的电脑那样来操作它们,而不被对方所发觉.2.木马:就是那些表面上伪装成了正常的程序,但是当这些被程序运行时,就会获取系统的整个控制权限.有很多黑客就是热中与使用木马程序来控制别人的电脑,比如灰鸽子,黑洞,PcShare等等.3.网页木马:表面上伪装成普通的网页文件或是将而已的代码直接插入到正常的网

移动平均値

#移动平均值:类似打靶每打一枪看平均环数 def average(): sum = 0 count = 0 avg = 0 while 1: num = yield avg sum+=num count+=1 avg=sum/count g = average() g.__next__() q=g.send(20) q=g.send(15) print(q) 原文地址:https://www.cnblogs.com/li33232/p/11443520.html

打靶归来——记参加射击比赛感想

打靶归来 --记参加射击比赛感想 实弹射击是所有军训项目中我最期待的一项,更令我感到兴奋和荣幸的是我竟能成为连里六个参加射击比赛的战士中的一员.我相信每一个男生曾经做过持枪战沙场梦,都曾在射击游戏中释放激情,都曾幻想自己射击时百步穿杨的雄风,而这次军训终于给了我们这样一个触摸真枪发射实弹的机会. 之前几日连队参加了射击预习,在拿枪之初没有人不欢欣鼓舞兴奋异常的,我们这些排在队伍后面的同学对能先摸枪的同学无不羡慕不已.经历漫长的等待后终于能够轮到我们进行射击预习.第一感觉就是枪重,枪在连长手中就跟