zoukankan      html  css  js  c++  java
  • Project Euler 88:Product-sum numbers 积和数

    Product-sum numbers

    A natural number, N, that can be written as the sum and product of a given set of at least two natural numbers, {a1, a2, … , ak} is called a product-sum number: N = a1 + a2 + … + ak = a1 × a2 × … × ak.

    For example, 6 = 1 + 2 + 3 = 1 × 2 × 3.

    For a given set of size, k, we shall call the smallest N with this property a minimal product-sum number. The minimal product-sum numbers for sets of size, k = 2, 3, 4, 5, and 6 are as follows.

    k=2: 4 = 2 × 2 = 2 + 2
    k=3: 6 = 1 × 2 × 3 = 1 + 2 + 3
    k=4: 8 = 1 × 1 × 2 × 4 = 1 + 1 + 2 + 4
    k=5: 8 = 1 × 1 × 2 × 2 × 2 = 1 + 1 + 2 + 2 + 2
    k=6: 12 = 1 × 1 × 1 × 1 × 2 × 6 = 1 + 1 + 1 + 1 + 2 + 6

    Hence for 2≤k≤6, the sum of all the minimal product-sum numbers is 4+6+8+12 = 30; note that 8 is only counted once in the sum.

    In fact, as the complete set of minimal product-sum numbers for 2≤k≤12 is {4, 6, 8, 12, 15, 16}, the sum is 61.

    What is the sum of all the minimal product-sum numbers for 2≤k≤12000?


    积和数

    若自然数N能够同时表示成一组至少两个自然数{a1, a2, … , ak}的积和和,也即N = a1 + a2 + … + ak = a1 × a2 × … × ak,则N被称为积和数。

    例如,6是积和数,因为6 = 1 + 2 + 3 = 1 × 2 × 3。

    给定集合的规模k,我们称满足上述性质的最小N值为最小积和数。当k = 2、3、4、5、6时,最小积和数如下所示:

    k=2: 4 = 2 × 2 = 2 + 2
    k=3: 6 = 1 × 2 × 3 = 1 + 2 + 3
    k=4: 8 = 1 × 1 × 2 × 4 = 1 + 1 + 2 + 4
    k=5: 8 = 1 × 1 × 2 × 2 × 2 = 1 + 1 + 2 + 2 + 2
    k=6: 12 = 1 × 1 × 1 × 1 × 2 × 6 = 1 + 1 + 1 + 1 + 2 + 6

    因此,对于2≤k≤6,所有的最小积和数的和为4+6+8+12 = 30;注意8只被计算了一次。

    已知对于2≤k≤12,所有最小积和数构成的集合是{4, 6, 8, 12, 15, 16},这些数的和是61。

    对于2≤k≤12000,所有最小积和数的和是多少?

    解题

     k个数的和 == k个数的积

    求对应k时候最小的这个数

    题目要求2≤k≤12000,时候的最小积数和的和

    参考题解中的程序,详解程序注释

    Java

    package Level3;
    
    
    import java.util.Set;
    import java.util.TreeSet;
    
    public class PE088{
        static void run(){
            int Kmin = 2;
            int Kmax = 12000;
            int sum = 0;
            Set<Integer> set = new TreeSet<Integer>();
            for(int k=Kmin;k<=Kmax;k++){
                int minN = getMin(k);
                if(set.add(minN))
                    sum+=minN;
            }
            System.out.println(sum);
        }
        // 找出k对于最小的n
        static int getMin(int k){
            for(int n=k+1;;n++){
                if(check(n,n,k))
                    return n;
            }
        }
        // 一个数拆成成k个数的和或者k个数的积 
        // prod 乘
        // sum 和 
        // 开始的时候这两个数是相等的  都是 prod 或者sum 拆分成k份 
        
    //    这里用到的是递归的方法,当 prod2 = prod1 * a ;sum2 = sum1- a 
    //            下面就可以检测下一轮了 check(prod2,sum2,k-1)
    //    这里用递归也是因为可能出  8 = 2*2*2*1*1 = 2+2+2+1+1  的形式,乘子中有数相同 的情况
    //    结束情况: 乘子是1的时候  sum == k k个1的和就是sum了
    //     k=1的时候  说明结束了 return prod == sum 
    //    下次递归可进行需要:d<= prod  k-1<= sum-d 下面程序很显然的 
        static boolean check(int prod,int sum,int k){
            if(sum <k) return false;
            if(prod == 1) return sum==k;
            if(k==1) return prod ==sum;
            for(int d =2;d<= prod && sum-d>=k-1;d++){
                if(prod%d==0){
                    if(check(prod/d,sum-d,k-1)) 
                        return true;
                }
            }
            return false;
        }
    //    7587457
    //    running time=1s577ms
        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");
    
        }
    }

    参考链接

    n[k]表示minimal product-sum numbers for size=k

    n[k]的上界为2*k,因为2*k总是能分解成2*k,然后2*k=k+2+(1)*(k-2)

    显然n[k]的下界为k

    对于一个数num   因式分解后因子个数为product   这些因子的和为sump

    则需要添加的1的个数为num-sump,所以size k=num-sump+product

    ===============================================

    上面说的很好理解

    在对于因式分解中

    n[k] 是 一个数分解成k个数的和  、k个数的积的最小值

    我上面链接中的程序的理解是通过因式分解,不断的缩小n[k]处的值,最终的值就是最小的,但是程序后面的递归理解不透。。。

    # coding=gbk
    
    import time as time 
    def run2():
        kMax = 12000
        n = [2*kMax for i in range(kMax)]
    
        def getpsn(num,sump,product,start):
            k = num - sump + product
            if k < kMax:
                if num<n[k]:
                    n[k] = num
                for i in range(start,kMax//num *2):
                    getpsn(num*i,sump+i,product + 1,i)
        getpsn(1,1,1,2)
        ans = sum(set(n[2:]))
        print ans 
    # 7587457
    # running time= 0.266000032425 s
    def run():
        kMin = 2
        kMax = 12000
        res=[]
        for k in range(kMin,kMax+1):
            minN = getMinN(k)
            if minN not in res:
                res.append(minN)
        print sum(minN)
               
    def getMinN(k):
        n = k + 1
        while(True):
            if check(n,n,k):
                return n 
            n +=1
            
    def check(prod,sum,k):
        if sum<k : return False
        if prod == 1:return sum==k 
        if k==1 :return prod ==sum
        for d in range(2,prod):
            if sum-d>=k-1 and prod%d ==0:
                if check(prod/d,sum-d,k-1):
                    return True 
        return False
    
    t0 = time.time()
    run2() 
    t1 = time.time()
    print "running time=",(t1-t0),"s"
    
    
                
  • 相关阅读:
    2017-2018-1 20155326 《信息安全系统设计基础》第六周课上作业
    20155326 2017-2018-1 《信息安全系统设计基础》缓冲区溢出漏洞实验
    2017-2018-1 201552326《信息安全技术》实验二——Windows口令破解
    《科技之巅2》序——机器智能数据智能:工具之王
    云大使成长精华指引(全)
    程序员职业规划课:如何开启"第二春"?
    明明可以靠脸吃饭偏要靠才华_你身边有女神程序员吗?
    6月19日云栖精选夜读:血泪总结!创业公司CTO要避免哪些坑?
    玩过这些经典单机游戏_就说明你已经老了
    帮程序员减压放松的10个良心网站
  • 原文地址:https://www.cnblogs.com/bbbblog/p/5002988.html
Copyright © 2011-2022 走看看