zoukankan      html  css  js  c++  java
  • POJ 1207 The 3n + 1 problem

    题目链接:http://poj.org/problem?id=1207

    题目大意:给你一个数x,规定一个函数F(x),如果x为1则F(x)==1,否则如果x是偶数,F(x)==F(x/2),x为奇数F(x)==F(3*x+1)计算给定x到变换到1的步数。

    注意点:

    1.提供的每组两个数字不一定是左边小右边大,所以可能要交换两者的值,另外,输出时必须要按两个数出现的顺序输出

    或者可以,先输出两个数,最后输出maxlen的值,保证在同一行即可

    2.直接枚举比较也是可以通过的,打表同样是可以的,因为数据范围不是很大

    3.其他的还有深搜法,记忆法什么的,参考网址:http://hi.baidu.com/wzyjerry/blog/item/f7c1e44481ced42586947347.html     深搜+记忆化

    方法一:直接枚举

    Memory: 3004K
    Time: 204MS

    import java.util.Scanner;
    
    public class Main{
    
        public static void main(String[] args) {
            Scanner sin=new Scanner(System.in);
            int start,end,len,maxlen,temp;
            while(sin.hasNext()){
                maxlen=0;
                temp=0;
                start=sin.nextInt();
                end=sin.nextInt();
                if(start>end){
                    temp=end;
                    end=start;
                    start=temp;
                }
                for(int i=start;i<=end;i++){
                    len=calculateLen(i);
                    if(len>maxlen){
                        maxlen=len;
                    }
                }
                if(temp==0){
                    System.out.println(start+" "+end+" "+(maxlen));
                }else{
                    System.out.println(end+" "+start+" "+(maxlen));
                }
            }
        }
        
        public static int calculateLen(int n){
            int len=1;
            while(n!=1){
                if(n%2==0){
                    n=n/2;
                }else{
                    n=3*n+1;
                }
                len++;
            }
            return len;
        }
    }

    方法二:打表   

    Memory: 3044K
    Time: 172MS

    import java.util.Scanner;
    
    public class Main{
        
        public static int[] lens=new int[10002];
    
        public static void main(String[] args) {
            Scanner sin=new Scanner(System.in);
            calculateLen();
            int start,end,maxlen,temp;
            while(sin.hasNext()){
                maxlen=0;
                temp=0;
                start=sin.nextInt();
                end=sin.nextInt();
                if(start>end){
                    temp=end;
                    end=start;
                    start=temp;
                }
                for(int i=start;i<=end;i++){
                    if(lens[i]>maxlen){
                        maxlen=lens[i];
                    }
                }
                if(temp==0){
                    System.out.println(start+" "+end+" "+(maxlen+1));//注意这里的括号(),不能少,不然会出现问题,将1看作了一个字符
                }else{
                    System.out.println(end+" "+start+" "+(maxlen+1));
                }
            }
        }
        
        public static void calculateLen(){
            int i,n;
            for(i=1;i<10002;i++){
                lens[i]=0;
                n=i;
                while(n!=1){
                    if(n%2==0){
                        n=n/2;
                    }else{
                        n=3*n+1;
                    }
                    lens[i]++;
                }
            }
        }
    }
    

    方法三:深搜+记忆优化

    Memory: 1024K
    Time: 0MS

    #include <iostream>
    #include <string.h>
    using namespace std;
    int M[200001];
    int Ans;
    int dfs(int n)
    {
        if(n==1)
            return 1;
        if(n>200000)
        {
            if(n%2==0)
                return dfs(n/2)+1;//这里就是深搜,此处向下递归了一层,后面加上 1
            else
                return dfs(n*3+1)+1;
        }
        if(!M[n])//判断是否已经求过n的长度,如果没有的话就去求,否则直接返回上次求得的值[记忆]
        {
            if(n%2==0)
                return M[n]=dfs(n/2)+1;
            else
                return M[n]=dfs(n*3+1)+1;
        }
        else
            return M[n];
    }
    int main()
    {
        int a,b;
        M[0]=1;
        for(int i=1; i<=10000; i++)
        {
            M[i]=dfs(i);//这里实际上就是打表,但是它主要的目的是保存那些频繁计算的数的长度
        }
        while(cin >> a >> b)
        {
            cout << a << ' ' << b << ' ';
            Ans=0;
            for(int i=min(a,b); i<=max(a,b); i++)
                Ans=max(Ans,M[i]);
            cout << Ans << endl;
        }
        return 0;
    }
    
     
  • 相关阅读:
    P1121 环状最大两段子段和
    无题
    cdoj 1485 柱爷搞子串 sam treap
    自然数幂和
    Gym 100341C AVL Trees NTT
    线性筛分解质因子
    codeforces 366 Ant Man dp
    UVALive 6914 Maze Mayhem 轮廓线dp
    hdu 5790 Prefix 字典树 主席树
    莫比乌斯反演个人小结
  • 原文地址:https://www.cnblogs.com/yinger/p/2107761.html
Copyright © 2011-2022 走看看