zoukankan      html  css  js  c++  java
  • 欧拉工程第70题:Totient permutation

    题目链接

     

    和上面几题差不多的

     

    Euler's Totient function, φ(n) [sometimes called the phi function]:小于等于n的数并且和n是互质的数的个数

    存在这样的数:N的欧拉数φ(n),是N的一个排列

    例如:φ(87109)=79180

     

    求在1---10^7中n/φ(n) 取到最小的 n 是多少?

    这里的是p是n的素因子,当素因子有相同的时候只取一个

    任意一个正整数都能分解成若干个素数乘积的形式

    直接利用上题的phi函数就可以求解

    这个是跑的最快的函数了

    long phi2(long n){
            long res = 0;
            if(n==1) return 0;
            int pi=2;
            res = n;
            while(pi*pi <=n){
                if(n%pi==0){
                    res/=pi;
                    res*=(pi-1);
                    while(n%pi==0){
                        n/=pi;
                    }
                    }
                pi++;
            }
            if(n>1){
                res/=n;
                res*=(n-1);
            }
            return res;
        }
    //    8319823
    //    running time=89s43ms

    运行结果也90s了

     

    然后考虑到

     

     

    这里的pi都是素数

    所以我们可以只考虑素数的情况

    当n%pi==0的时候这个pi就符合条件,并去重

    void run2(){
            long Max_n = 10000000;    
            int Prime_len=400;
            int[] Prime = new int[Prime_len];
            Prime[0] = 2;
            int k=1;
            int p=1;
            while(k<Prime_len){
                if(isPrime(p)){ 
                    Prime[k++] = p;
                }
                p+=2;
            }
            
            long result = 0;
            double minvalue=10000;
            long euler = 0 ;
            for(long n = 2;n<Max_n;n++){
                euler = phi3(n,Prime);
                if(isPerm(euler,n)){
                    double temp = n/(euler*1.0);
                    if(temp<minvalue){
                        minvalue = temp;
                        result = n;
                    }
                }
            }
            System.out.println(result);
    
        }

    结果:

    //    8319823
    //    running time=58s426ms

    时间少了30s

     

    这里缺点是要取多少个素数?

    我从100,200,300,400,在400的时候结果是正确的

     

    全部程序:

    package project61;
    
    public class P70{
        void run2(){
            long Max_n = 10000000;    
            int Prime_len=400;
            int[] Prime = new int[Prime_len];
            Prime[0] = 2;
            int k=1;
            int p=1;
            while(k<Prime_len){
                if(isPrime(p)){ 
                    Prime[k++] = p;
                }
                p+=2;
            }
            
            long result = 0;
            double minvalue=10000;
            long euler = 0 ;
            for(long n = 2;n<Max_n;n++){
                euler = phi3(n,Prime);
                if(isPerm(euler,n)){
                    double temp = n/(euler*1.0);
                    if(temp<minvalue){
                        minvalue = temp;
                        result = n;
                    }
                }
            }
            System.out.println(result);
    
        }
    //    8319823
    //    running time=58s426ms
        
        long phi3(long n,int[]  Prime){
            long res = 0;
            if(n==1) return 0;
            int len = Prime.length;
            res = n;
            int i=0; //&& n>=Prime[i]
            while(i <len && n>=Prime[i] ){
                if(n%Prime[i]==0){
                    res/=Prime[i];
                    res*=(Prime[i]-1);
                    while(n%Prime[i]==0){
                        n/=Prime[i];
                    }
                    }
                i++;
            }
            if(n>1){
                res/=n;
                res*=(n-1);
            }
            return res;
        }
        void run(){
            long Max_n = 10000000;    
            long result = 0;
            double minvalue=10000;
            long euler = 0 ;
            for(long n = 2;n<Max_n;n++){
                euler = phi2(n);
                if(isPerm(euler,n)){
                    double temp = n/(euler*1.0);
                    if(temp<minvalue){
                        minvalue = temp;
                        result = n;
                    }
                }
            }
            System.out.println(result);
        }
        boolean isPerm(long a,long b){
            int[] label = new int[10];
            while(a!=0&&b!=0){
                label[(int) (a%10)]+=1;
                label[(int) (b%10)]-=1;
                a/=10;
                b/=10;
                
            }
            if(a!=0) return false;
            if(b!=0) return false;
            for(int i=0;i<10;i++)
                if(label[i]!=0) 
                    return false;
            return true;
        }
        
        boolean isPrime(int n){
            if(n==2||n==3||n==5||n==7||n==11) return true;
            if(n<2||n%2==0||n%3==0) return false;
            for(int i=5;i<=Math.sqrt(n)+1;i++){
                if(n%i==0) return false;
            }
            return true;
        }
        
        long phi2(long n){
            long res = 0;
            if(n==1) return 0;
            int pi=2;
            res = n;
            while(pi*pi <=n){
                if(n%pi==0){
                    res/=pi;
                    res*=(pi-1);
                    while(n%pi==0){
                        n/=pi;
                    }
                    }
                pi++;
            }
            if(n>1){
                res/=n;
                res*=(n-1);
            }
            return res;
        }
    //    8319823
    //    running time=89s43ms
    //
        
        public static void main(String[] args){
            
            long start = System.currentTimeMillis();
            new P70().run2();
            long end = System.currentTimeMillis();
            long time = end - start;
            System.out.println("running time="+time/1000+"s"+time%1000+"ms");
            
        }
    }

    一直感觉这个程序还可以优化

    是否还有好的算法

    大笑

    在解题论坛上,有个解答程序看不懂,然后我就敲成java,用时8s。。。快了好多的

    long[] cal_phi(){
            long[] phi=new long[Max_n+1];
            for(int i=1;i<Max_n;i++){
                phi[i]+=i;
                for(int j=2*i;j<Max_n;j+=i)
                    phi[j]-=phi[i];
            }
            return phi;
        }

    8s

    这个是产生Max_n的所以的欧拉函数,这个虽然是两层循环,但是效率很高的,变量完就得到欧拉函数值

     

    下面一种形式:

    long[] cal_phi2(){
            long[] phi = new long[Max_n+1];
            for(int i=1;i<Max_n;i++)
                phi[i] = i;
            for(int i=2;i<Max_n;i++){
                if(phi[i]==i)
                    phi[i] = i - 1;
                for(int j=2*i;j<Max_n;j+=i)
                    phi[j]*=(1-1.0/i);
            }
            return phi;
        }

    15s

    //    8319823
    //    running time=14s577ms

    至于上面是何总介绍?我还不明白

     

    在解题报告中,还有一种是利用到素数,奇数,偶数还不明白为什么的。

    全部程序:

    package project61;
    
    public class P70_1{
        int Max_n = 10000000;
        void run(){
            long[] phi=cal_phi();
            int result = 0;
            double minvalue = 10000.0;
            for(int n=2;n<Max_n;n++){
                long euler = phi[n];
                if(isPerm(euler,n)){
                    double temp = n/(euler*1.0);
                    if(temp<minvalue){
                        minvalue = temp;
                        result = n;
                    }
                }
                
            }
            System.out.println(result);
            
        }
        
        long[] cal_phi(){
            long[] phi=new long[Max_n+1];
            for(int i=1;i<Max_n;i++){
                phi[i]+=i;
                for(int j=2*i;j<Max_n;j+=i)
                    phi[j]-=phi[i];
            }
            return phi;
        }
    //    8319823
    //    running time=7s855ms
        long[] cal_phi2(){
            long[] phi = new long[Max_n+1];
            for(int i=1;i<Max_n;i++)
                phi[i] = i;
            for(int i=2;i<Max_n;i++){
                if(phi[i]==i)
                    phi[i] = i - 1;
                for(int j=2*i;j<Max_n;j+=i)
                    phi[j]*=(1-1.0/i);
            }
            return phi;
        }
    //    8319823
    //    running time=14s577ms
        boolean isPerm(long a,long b){
            int[] label = new int[10];
            while(a!=0&&b!=0){
                label[(int) (a%10)]+=1;
                label[(int) (b%10)]-=1;
                a/=10;
                b/=10;
                
            }
            if(a!=0) return false;
            if(b!=0) return false;
            for(int i=0;i<10;i++)
                if(label[i]!=0) 
                    return false;
            return true;
        }
        
        
        boolean isPrime(long n){
            if(n==2||n==3||n==5||n==7) return true;
            if(n<2||n%2==0||n%3==0) return false;
            for(int i=5;i<=Math.sqrt(n);i++)
                if(n%i==0) return false;
            return true;
        }
        public static void main(String[] args){
            long start = System.currentTimeMillis();
            new P70_1().run();
            long end = System.currentTimeMillis();
            long time = end - start;
            System.out.println("running time="+time/1000+"s"+time%1000+"ms");
        }
    }

    上面的程序用Python实习时间好长的大笑

  • 相关阅读:
    你知道这高效的12个Java精品库嘛?
    一篇文章带你吃透,Java界最神秘技术ClassLoader
    带你认真了解一下Java分布式系统的基本特性
    因为选定的用户拥有对象,所以无法除去该用户
    mysql自定义函数与过程中写法的注意事项
    使用nssm在windows服务器上部署nodejs
    shopnc 手机网站配置
    关于navicat远程连接mysql问题
    KindEditor 4.1.2版本,在上传图片的时候 设置为绝对路径
    微信分享图标制作
  • 原文地址:https://www.cnblogs.com/theskulls/p/4838715.html
Copyright © 2011-2022 走看看