• Project Euler 76:Counting summations


    题目链接

    原题:

    It is possible to write five as a sum in exactly six different ways:

    4 + 1
    3 + 2
    3 + 1 + 1
    2 + 2 + 1
    2 + 1 + 1 + 1
    1 + 1 + 1 + 1 + 1

    How many different ways can one hundred be written as a sum of at least two positive integers?

    翻译:

    加和计数

    将5写成整数的和有6种不同的方式:

    4 + 1
    3 + 2
    3 + 1 + 1
    2 + 2 + 1
    2 + 1 + 1 + 1
    1 + 1 + 1 + 1 + 1

    将100写成整数的和有多少种不同的方式?

    翻译来源

    解题思路:

    将100能够拆成整数的和能够有多少种?

    1.利用动态规划求解

    2.利用数的拆分求解<组合数学中有讲解>

    数的拆分法

    理论基础,链接中讲到了拆分的理论

    image

    P(n,k)的意思就是n拆分成k份的数量

    有递推公式:

    P(n,k)= P(n-1,k-1) + P(n-k,k)

    初始值:

    k>n时:P(n,k) = 0

    对所有的n,P(n,n)=1,P(n,0)=0

    也很显然的发现:

    对所有的n,P(n,1)=n,P(n,2) = n/2 的向下取整

    证明:P(n,k)= P(n-1,k-1) + P(n-k,k)

    忘了。。。

    求出所以的P(n,k)矩阵

    则n的所以拆分的和是 image

    Java程序:

    //  整数n 拆分k份
        void partitions(){
            int limit = 100;
            int count = 0;
            int[][] p = new int[limit+1][limit+1];
            for(int n=0;n<=limit;n++){
                p[n][n] = 1;
                p[n][1] = 1;
                p[n][0] = 0;
            }
            for(int n=1;n<=limit;n++){
                for(int k=1;k<=n;k++){
                    p[n][k] = p[n-1][k-1] + p[n-k][k];
                        if(n==limit)
                            count+=p[n][k];
                    }
            }
            count = count - 1;
            System.out.println(count);
        }

    结果:

    //    190569291
    //    running time=0s0ms

    利用递归程序:

    void getPar(){
            int limit = 100;
            int count = 0;
            for(int k=1;k<=limit;k++)
                count+=Par(100,k);
            count = count-1;
            System.out.println(count);
        }
    
        //递归形式 整数n 拆分k分
        int Par(int n,int k){
            if(k==1||n==k) return 1;
            if(k>n) return 0;
            return Par(n-1,k-1)+Par(n-k,k);
        }

    结果:

    //    190569291
    //    running time=1s869ms

    递归时间明显长了许多

    动态规划求解

    //动态规划求解
        void dp(){
            int limit = 100;
            int[] ways = new int[limit+1];
            ways[0] = 1 ;
            for(int i=1;i<=limit-1;i++){
                for(int j = i;j<=limit;j++)
                    ways[j] += ways[j-i];
            }
            System.out.println(ways[limit]);
        }
    //    190569291
    //    running time=0s0ms

    还看不懂吸血蝙蝠

    完整java程序:

    package Level3;
    public class PE076{
        
        void run(){
    
    //        dp();
    //        partitions();
    //        getPar();
            int res = partitions3(100,100);
            res = res - 1;
            System.out.println(res);
        }
        int  partitions3(int n,int m ){
            if(n<=1) return 1;
            if(m>n) return partitions3(n,n);
            int sum = 0;
            for(int k=1;k<=m;k++)
                sum+=partitions3(n-k,k);
            return sum;
        }
    //    190569291
    //    running time=10s845ms
        void getPar(){
            int limit = 100;
            int count = 0;
            for(int k=1;k<=limit;k++)
                count+=Par(100,k);
            count = count-1;
            System.out.println(count);
        }
    //    190569291
    //    running time=1s869ms
        //递归形式 整数n 拆分k分
        int Par(int n,int k){
            if(k==1||n==k) return 1;
            if(k>n) return 0;
            return Par(n-1,k-1)+Par(n-k,k);
        }
        //  整数n 拆分k份
        void partitions(){
            int limit = 100;
            int count = 0;
            int[][] p = new int[limit+1][limit+1];
            for(int n=0;n<=limit;n++){
                p[n][n] = 1;
                p[n][1] = 1;
                p[n][0] = 0;
            }
            for(int n=1;n<=limit;n++){
                for(int k=1;k<=n;k++){
                    p[n][k] = p[n-1][k-1] + p[n-k][k];
                        if(n==limit)
                            count+=p[n][k];
                    }
            }
            count = count - 1;
            System.out.println(count);
    //        for(int n=1;n<=6;n++){
    //            for(int k=1;k<=n;k++)
    //                System.out.print(p[n][k]+" ");
    //            System.out.println();
    //        }
            
    //        for(int k=0;k<=limit;k++)
    //            count+= p[limit][k];
    //        count = count - 1;
    //        System.out.println(count);
            
        }
    //    190569291
    //    running time=0s0ms
        //动态规划求解
        void dp(){
            int limit = 100;
            int[] ways = new int[limit+1];
            ways[0] = 1 ;
            for(int i=1;i<=limit-1;i++){
                for(int j = i;j<=limit;j++)
                    ways[j] += ways[j-i];
            }
            System.out.println(ways[limit]);
        }
    //    190569291
    //    running time=0s0ms
        
        
        public static void main(String[] args){
            long t0 = System.currentTimeMillis();
            new PE076().run();
            long t1 = System.currentTimeMillis();
            long t = t1 - t0;
            System.out.println("running time="+t/1000+"s"+t%1000+"ms");
            
        }
    }

    Python实现

    动态规划的效率很高

    递归的已经不能忍了

    import time 
    
    def PE076():
        res = dp();
    #     res = partitions(100,100)
        print res 
    def partitions(n,m):
    #     limit = 100 
        count = 0 
        if n<=1 : return 1
        if m>n : return partitions(n,n)
        for k in range(1,m+1):
            count = count + partitions(n-k,k)
        return count
    #     190569292
    # running time=1073.04099989s
    def dp():
        limit = 100
        ways = [0]*(limit+1)
        ways[0] = 1 
        for n in range(1,limit):
            for k in range(n,limit+1):
                ways[k] +=ways[k-n]
        return ways[limit]
    if __name__=='__main__':
        t0 = time.time()
        PE076()
        print "running time={0}s".format((time.time()-t0))
  • 相关阅读:
    DotNetty网络通信框架学习之初识Netty
    DotNetty网络通信框架学习
    DotNetty网络通信框架学习之源码分析
    MODBUS协议解析中常用的转换帮助类(C#)
    C# 键盘钩子
    C# 实现http不同方法的请求
    C# 中List<T>与DataSet之间的转换
    C# 将文件夹中文件复制到另一个文件夹
    WinForm中 Asp.Net Signalr消息推送测试实例
    redis安装教程
  • 原文地址:https://www.cnblogs.com/theskulls/p/4851958.html
Copyright © 2020-2023  润新知