Project Euler 109 :Darts 飞镖

Darts

In the game of darts a player throws three darts at a target board which is split into twenty equal sized sections numbered one to twenty.

The score of a dart is determined by the number of the region that the dart lands in. A dart landing outside the red/green outer ring scores zero. The black and cream regions inside this ring represent single scores. However, the red/green outer ring and middle ring score double and treble scores respectively.

At the centre of the board are two concentric circles called the bull region, or bulls-eye. The outer bull is worth 25 points and the inner bull is a double, worth 50 points.

There are many variations of rules but in the most popular game the players will begin with a score 301 or 501 and the first player to reduce their running total to zero is a winner. However, it is normal to play a “doubles out” system, which means that the player must land a double (including the double bulls-eye at the centre of the board) on their final dart to win; any other dart that would reduce their running total to one or lower means the score for that set of three darts is “bust”.

When a player is able to finish on their current score it is called a “checkout” and the highest checkout is 170: T20 T20 D25 (two treble 20s and double bull).

There are exactly eleven distinct ways to checkout on a score of 6:

     
D3    
D1 D2  
S2 D2  
D2 D1  
S4 D1  
S1 S1 D2
S1 T1 D1
S1 S3 D1
D1 D1 D1
D1 S2 D1
S2 S2 D1

Note that D1 D2 is considered different to D2 D1 as they finish on different doubles. However, the combination S1 T1 D1 is considered the same as T1 S1 D1.

In addition we shall not include misses in considering combinations; for example, D3 is the same as 0 D3 and 0 0 D3.

Incredibly there are 42336 distinct ways of checking out in total.

How many distinct ways can a player checkout with a score less than 100?



飞镖

在飞镖游戏中,玩家需向靶子上投掷三枚飞镖;靶子被分成了二十个相等面积的区域,并分别标上1至20。

每一枚飞镖的分数还取决于它的位置。落在外围的红/绿色圈以外时为零分,落在黑/白色区域时为一倍得分,而落在外围和中间的红/绿色圈时分别为两倍和三倍得分。

在把子的正中心有两个同心圆,被称为靶心。射中靶心外圈得25分,射中靶心内圈则得双倍50分。

飞镖的规则有许多变种,但最热门的一种是,每个玩家从301分或501分开始,轮流投掷飞镖并减去得分,首先将自己的分数减少到恰好为0的玩家获胜。不过,通常会采用“双倍结束”规则,即玩家在最后一镖必须射中一个双倍区域(包括双倍的靶心内圈)才能判定获胜。若这一轮的得分使得玩家的分数减少到1分或更少,但最后一镖未射中双倍区域,则这一轮的得分“作废”。

玩家在目前的分数下能够获胜则被称为“结分”。最高的结分为170:T20 T20 D25(两个三倍20分和一个双倍靶心)。

当玩家分数为6时,恰好有11种结分方式:

     
D3    
D1 D2  
S2 D2  
D2 D1  
S4 D1  
S1 S1 D2
S1 T1 D1
S1 S3 D1
D1 D1 D1
D1 S2 D1
S2 S2 D1

注意D1 D2被认为是不同于D2 D1的结分方式,因为它们最后的双倍不同。不过,组合S1 T1 D1和T1 S1 D1就被认为是相同的结分方式。

另外,我们在计算组合时,我们不考虑脱靶的情况;例如,D3和0 D3以及0 0 D3就是相同的结分方式。

令人惊奇的是一共有42336种不同的结分方式。

当玩家分数小于100时,一共有多少种不同的结分方式?

解题

飞镖盘官网  看到下面的图

对上面讲的瞬间懂了

理解题意:表盘上的的数组有 1-20、1-20的两倍数、1-20的三倍数、25、50

结分:射击所得分数与自己目前所余分数一样,也就是相减为0,自己是零分。

结分的方式:最后一镖必须射中一个双倍区域

具体分为下面的情况:

1.射击一次结束:一定是双倍数区域

2.射击两次结束:第二次一定是双倍数区域

3.射击三次结束:第三次一定是双倍数区域

Java

package Level4;

import java.util.ArrayList;
import java.util.List;

public class PE0109{
    public static void run(){
        int limit = 100;
        int res = 0;
        List<Integer> scores = new ArrayList<Integer>();
        for(int i =1;i<=20;i++){
            scores.add(i);
            scores.add(2*i);
            scores.add(3*i);
        }
        scores.add(25);
        scores.add(50);
        List<Integer> doubles = new ArrayList<Integer>();
        for(int i=1;i<=20;i++){
            doubles.add(2*i);
        }
        doubles.add(50);
        // 射中双倍结束
        for(int i=0;i<doubles.size();i++){
            if(doubles.get(i) <limit)
                res++;
        }
        // 射击两次结束
        for(int i=0;i< scores.size();i++){
            for(int j=0;j<doubles.size();j++){
                if(scores.get(i)+doubles.get(j) <limit){
                    res++;
                }
            }
        }
        // 射击三次结束
        for(int i=0;i<scores.size();i++){
            for(int j=i;j<scores.size();j++){
                for(int k=0;k<doubles.size();k++){
                    if(scores.get(i)+scores.get(j)+doubles.get(k) <limit){
                        res++;
                    }
                }
            }
        }
        System.out.println(res);

    }

    public static void main(String[] args){
        long t0 = System.currentTimeMillis();
        run();
        long t1 = System.currentTimeMillis();
        long t = t1 - t0;
        System.out.println("running time="+t/1000+"s"+t%1000+"ms");
    }
}

Java Code

38182
running time=0s8ms

Python

# coding=gbk

def run1():
    from itertools import combinations_with_replacement

    CHECKOUT_LIMIT = 100

    # define dart combinations
    SINGLE = range(1, 20+1)
    DOUBLE = [2*i for i in SINGLE] + [50]
    TREBLE = [3*i for i in SINGLE]
    ANY_SCORE = SINGLE + [25] + DOUBLE + TREBLE

    # throw type 1 - 3 darts - hit, hit, double
    throw1 = [(d1, d2, d3) for (d1, d2) in combinations_with_replacement(ANY_SCORE, 2) for d3 in DOUBLE]

    # throw type 2 - miss, hit, double
    throw2 = [(0, d1, d2) for d1 in ANY_SCORE for d2 in DOUBLE]

    # throw type 3 - miss, miss, double
    throw3 = [(0, 0, d1) for d1 in DOUBLE]

    # calculate checkout total that meets conditions
    checkout_tot = sum(1 for (d1, d2, d3) in throw1 + throw2 + throw3 if sum((d1, d2, d3)) < CHECKOUT_LIMIT)

    print checkout_tot
def run():
    res = 0
    singles = []
    doubles = []
    trebles = []

    for i in range(1, 21):
        singles.append(i)
        doubles.append(2*i)
        trebles.append(3*i)
    singles.append(25)
    doubles.append(50)
    scores = []
    scores += singles
    scores += doubles
    scores += trebles

    for s in doubles:
        if s<100:
            res+=1
    for s1 in scores:
        for s2 in doubles:
            if s1+s2 < 100:
                res+=1
    for i in range(len(scores)):
        for j in range(i,len(scores)):
            for s in doubles:
                if scores[i] + scores[j] + s< 100:
                    res+=1
    print res 

if __name__ == ‘__main__‘:
    run()
    run1()
    
时间: 2024-10-09 20:55:38

Project Euler 109 :Darts 飞镖的相关文章

Python练习题 048:Project Euler 021:10000以内所有亲和数之和

本题来自 Project Euler 第21题:https://projecteuler.net/problem=21 ''' Project Euler: Problem 21: Amicable numbers Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n). If d(a) = b and d(b) = a, where a ≠ b

Python练习题 047:Project Euler 020:阶乘结果各数字之和

本题来自 Project Euler 第20题:https://projecteuler.net/problem=20 ''' Project Euler: Problem 20: Factorial digit sum n! means n × (n ? 1) × ... × 3 × 2 × 1 For example, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800, and the sum of the digits in the number 10! i

Python练习题 046:Project Euler 019:每月1日是星期天

本题来自 Project Euler 第19题:https://projecteuler.net/problem=19 ''' How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)? Answer: 171 ''' from datetime import * firstDay = date(1901,1,1) lastDay = date(

Python练习题 035:Project Euler 007:第10001个素数

本题来自 Project Euler 第7题:https://projecteuler.net/problem=7 # Project Euler: Problem 7: 10001st prime # By listing the first six prime numbers: # 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13. # What is the 10 001st prime number? # Answer

Python练习题 034:Project Euler 006:和平方与平方和之差

本题来自 Project Euler 第6题:https://projecteuler.net/problem=6 # Project Euler: Problem 6: Sum square difference # The sum of the squares of the first ten natural numbers is, # 1**2 + 2**2 + ... + 10**2 = 385 # The square of the sum of the first ten natur

Project Euler 126 - Cuboid layers

这题先是推公式- 狂用不完全归纳+二次回归,最后推出这么一个奇怪的公式 f(t,x,y,z)=4(t?1)(x+y+z+t?2)+2(xy+yz+xz) 表示长宽高为x .y .z 的立方体第t 层放的立方体的个数. 接下来就是算答案了- 方法很简单:暴力 但是暴力还是有技巧的,开始我是直接从1到1000枚举t .x .y .z ,但这样出不来结果. 换成下面代码里的方法就行了. 1 #include <iostream> 2 #include <cstdio> 3 #includ

Project Euler 第一题效率分析

Project Euler: 欧拉计划是一系列挑战数学或者计算机编程问题,解决这些问题需要的不仅仅是数学功底. 启动这一项目的目的在于,为乐于探索的人提供一个钻研其他领域并且学习新知识的平台,将这一平台打造一个有趣和休闲 的环境. 项目主页:https://projecteuler.net 第一题 Multiples of 3 and 5 If we list all the natural numbers below 10 that are multiples of 3 or 5, we ge

Python练习题 042:Project Euler 014:最长的考拉兹序列

本题来自 Project Euler 第14题:https://projecteuler.net/problem=14 ''' Project Euler: Problem 14: Longest Collatz sequence The following iterative sequence is defined for the set of positive integers: n → n/2 (n is even) n → 3n + 1 (n is odd) Using the rule

Python练习题 041:Project Euler 013:求和、取前10位数值

本题来自 Project Euler 第13题:https://projecteuler.net/problem=13 # Project Euler: Problem 13: Large sum # Work out the first ten digits of the sum of the following one-hundred 50-digit numbers. # Answer: 5537376230 numbers = '''371072875339021027987979982