zoukankan      html  css  js  c++  java
  • 算法笔记_109:第四届蓝桥杯软件类省赛真题(JAVA软件开发本科B组部分习题)试题解答

     目录

    1 马虎的算式

    2 黄金连分数

    3 有理数类

    4 幸运数

    5 连号区间数

     

    前言:以下试题解答代码部分仅供参考,若有不当之处,还请路过的同学提醒一下~


    1 马虎的算式

    标题: 马虎的算式
    
    
        小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。
    
        有一次,老师出的题目是:36 x 495 = ?
    
        他却给抄成了:396 x 45 = ?
    
        但结果却很戏剧性,他的答案竟然是对的!!
    
        因为 36 * 495 = 396 * 45 = 17820
    
        类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54
    
        假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)
    
        能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?
    
    
    请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。
    
    满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数。
    
    
    答案直接通过浏览器提交。
    注意:只提交一个表示最终统计种类数的数字,不要提交解答过程或其它多余的内容。
    
    142
    方法1(暴力枚举):
    import java.util.ArrayList;
    import java.util.Collections;
    
    public class Main {
        public static int count = 0;
        //判断A和B是否是否1~9中不同的5个数字组成
        public boolean judge(int A, int B) {
            ArrayList<Integer> list = new ArrayList<Integer>();
            while(A > 0) {
                list.add(A % 10);
                A = A / 10;
            }
            while(B > 0) {
                list.add(B % 10);
                B = B / 10;
            }
            Collections.sort(list);
            for(int i = 1;i < list.size();i++) {
                if(list.get(i - 1) == 0 || list.get(i - 1) == list.get(i))
                    return false;
            }
            return true;
        }
        
        public void printResult() {
            for(int a = 10;a < 100;a++) {
                for(int b = 100;b < 1000;b++) {
                    if(judge(a, b)) {
                        int a1 = a % 10;
                        int a2 = a / 10;
                        int b1 = b % 10;
                        int b2 = b / 10 % 10;
                        int b3 = b / 100;
                        if(a * b == (a2*100 + b2*10 + a1) * (b3*10 + b1)) {
                            count++;
                        }
                    }
                }
            }
        }
        
        public static void main(String[] args) {
            Main test = new Main();
            test.printResult();
            System.out.println(count);
        }
    }
    方法2(dfs全排列枚举):
    import java.util.ArrayList;
    
    public class Main1 {
        public static int count = 0;
        
        public void check(ArrayList<Integer> list) {
            int a = list.get(0);
            int b = list.get(1);
            int c = list.get(2);
            int d = list.get(3);
            int e = list.get(4);
            int num1 = (a*10 + b) * (c*100 + d*10 + e);
            int num2 = (a*100 + d*10 + b) * (c*10 + e);
            if(num1 == num2)
                count++;
            return;
        }
        //dfs求取1~9中随机五个不同数字的全排列
        public void dfs(ArrayList<Integer> list, int step) {
            if(step == 5) {
                check(list);
                return;
            } else {
                for(int i = 1;i < 10;i++) {
                    if(list.contains(i))
                        continue;
                    list.add(i);
                    dfs(list, step + 1);
                    list.remove(list.size() - 1);
                }
            }
            return;
        }
        
        public static void main(String[] args) {
            Main1 test = new Main1();
            ArrayList<Integer> list = new ArrayList<Integer>();
            test.dfs(list, 0);
            System.out.println(count);
        }
    }

    2 黄金连分数

    标题: 黄金连分数
    
    
        黄金分割数0.61803... 是个无理数,这个常数十分重要,在许多工程问题中会出现。有时需要把这个数字求得很精确。
    
        对于某些精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加工错误,对那样一个庞然大物,其实只是镜面加工时有比头发丝还细许多倍的一处错误而已,却使它成了“近视眼”!!
    
    
        言归正传,我们如何求得黄金分割数的尽可能精确的值呢?有许多方法。
    
        比较简单的一种是用连分数:
    
                      1
        黄金数 = ---------------------
                            1
                 1 + -----------------
                              1
                     1 + -------------
                                1
                         1 + ---------
                              1 + ...
    
                               
    
        这个连分数计算的“层数”越多,它的值越接近黄金分割数。
    
        请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。
    
        小数点后3位的值为:0.618
        小数点后4位的值为:0.6180
        小数点后5位的值为:0.61803
        小数点后7位的值为:0.6180340
       (注意尾部的0,不能忽略)
    
    
    你的任务是:写出精确到小数点后100位精度的黄金分割值。
    
    注意:尾数的四舍五入! 尾数是0也要保留!
    
    显然答案是一个小数,其小数点后有100位数字,请通过浏览器直接提交该数字。
    注意:不要提交解答过程,或其它辅助说明类的内容。
    
    0.6180339887498948481971959525508621220510663574518538453723187601229582821971784348083863296133320592(求取fib(48) / fib(49)的精度)
    
    0.6180339887498948482045868343656381177203091798057628621354486227052604628189024496923340122463725714(求取fib(198)/fib(199)的精度)
    
    0.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911375(求取fib(49998)/fib(49999)的精度)
    此处,个人建议求取精度的问题,尽量做到当前自己能够使用计算机算的最大精度,所以最好选择fib(49998)/fib(49999)的结果。
    
    轻易可知fib(100)以上的数基本上已经超过long型整数的范围了,此处可以借用大整数类型完成更加精确的计算。
    import java.math.BigDecimal;
    import java.math.BigInteger;
    
    public class Main {
        
        public static void main(String[] args) {
            BigInteger[] A = new BigInteger[50000];
            A[0] = new BigInteger("0");
            A[1] = new BigInteger("1");
            for(int i = 2;i < 50000;i++) {
                A[i] = A[i - 1].add(A[i - 2]);//迭代求取斐波那契数(i值越大,求取结果精度越大)
            }
            BigDecimal a = new BigDecimal(A[49998]);
            BigDecimal b = new BigDecimal(A[49999]);
            System.out.println(a.divide(b, 100, BigDecimal.ROUND_HALF_UP));
        }
    }

    3 有理数类

    标题:有理数类
    
        有理数就是可以表示为两个整数的比值的数字。一般情况下,我们用近似的小数表示。但有些时候,不允许出现误差,必须用两个整数来表示一个有理数。
    
        这时,我们可以建立一个“有理数类”,下面的代码初步实现了这个目标。为了简明,它只提供了加法和乘法运算。
    
    class Rational
    {
        private long ra;
        private long rb;
        
        private long gcd(long a, long b){
            if(b==0) return a;
            return gcd(b,a%b);
        }
        public Rational(long a, long b){
            ra = a;
            rb = b;    
            long k = gcd(ra,rb);
            if(k>1){ //需要约分
                ra /= k;  
                rb /= k;
            }
        }
        // 加法
        public Rational add(Rational x){
            return ________________________________________;  //填空位置
        }
        // 乘法
        public Rational mul(Rational x){
            return new Rational(ra*x.ra, rb*x.rb);
        }
        public String toString(){
            if(rb==1) return "" + ra;
            return ra + "/" + rb;
        }
    }
    
    使用该类的示例:
        Rational a = new Rational(1,3);
        Rational b = new Rational(1,6);
        Rational c = a.add(b);
        System.out.println(a + "+" + b + "=" + c);
    
    
    请分析代码逻辑,并推测划线处的代码,通过网页提交
    注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!
    
    
    new Rational(x.ra*rb + ra*x.rb, x.rb*rb)

    4 幸运数

    标题:幸运数
    
        幸运数是波兰数学家乌拉姆命名的。它采用与生成素数类似的“筛法”生成。
    
        首先从1开始写出自然数1,2,3,4,5,6,....
        
        1 就是第一个幸运数。
        我们从2这个数开始。把所有序号能被2整除的项删除,变为:
    
        1 _ 3 _ 5 _ 7 _ 9 ....
    
        把它们缩紧,重新记序,为:
        
        1 3 5 7 9 .... 。这时,3为第2个幸运数,然后把所有能被3整除的序号位置的数删去。注意,是序号位置,不是那个数本身能否被3整除!! 删除的应该是5,11, 17, ...
    
        此时7为第3个幸运数,然后再删去序号位置能被7整除的(19,39,...) 
    
        最后剩下的序列类似:
    
        1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, ...
    
    本题要求:
    
    输入两个正整数m n, 用空格分开 (m < n < 1000*1000)
    程序输出 位于m和n之间的幸运数的个数(不包含m和n)。
    
    例如:
    用户输入:
    1 20
    程序输出:
    5
    
    例如:
    用户输入:
    30 69
    程序输出:
    8
    
    
    
    资源约定:
    峰值内存消耗(含虚拟机) < 64M
    CPU消耗  < 2000ms
    
    
    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
    
    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
    注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
    注意:主类的名字必须是:Main,否则按无效代码处理。
    import java.util.ArrayList;
    import java.util.Scanner;
    
    public class Main {
        
        public void printResult(int m, int n) {
            ArrayList<Integer> list = new ArrayList<Integer>();
            list.add(-1);   //第0位存-1,后面才开始存幸运数,方便后面删除操作
            for(int i = 1;i < n;i++) {
                if(i % 2 == 0) 
                    continue;
                list.add(i);
            }
            int count = 2;  //开始遍历的幸运数位置
            while(true) {
                int start = list.get(count);
                ArrayList<Integer> list1 = new ArrayList<Integer>();
                list1.add(-1);
                for(int i = 1;i < list.size();i++) {
                    if(i % start == 0)
                        continue;
                    else {
                        list1.add(list.get(i));
                    }
                }
                list = list1;
                count++;
                if(count > list.size() - 1)
                    break;
            }
            list.remove(0);    //删除第0位-1情况
            int i = 0;
            for(;i < list.size();i++) {
                if(list.get(i) > m)
                    break;
            }
            int result = list.size() - i;
            System.out.println(result);
        }
        
        public static void main(String[] args) {
            Main test = new Main();
            Scanner in = new Scanner(System.in);
            int m = in.nextInt();
            int n = in.nextInt();
            test.printResult(m, n);
        }
    }

    5 连号区间数

    标题:连号区间数
    
        小明这些天一直在思考这样一个奇怪而有趣的问题:
    
        在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:
    
        如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为R-L+1的“连续”数列,则称这个区间连号区间。
    
        当N很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。
    
    输入格式:
    第一行是一个正整数N (1 <= N <= 50000), 表示全排列的规模。
    第二行是N个不同的数字Pi(1 <= Pi <= N), 表示这N个数字的某一全排列。
    
    输出格式:
    输出一个整数,表示不同连号区间的数目。
    
    示例:
    用户输入:
    4
    3 2 4 1
    
    程序应输出:
    7
    
    用户输入:
    5
    3 4 2 5 1
    
    程序应输出:
    9
    
    解释:
    第一个用例中,有7个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [2,2], [3,3], [4,4]
    第二个用例中,有9个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [1,5], [2,2], [3,3], [4,4], [5,5]
    
    
    资源约定:
    峰值内存消耗(含虚拟机) < 64M
    CPU消耗  < 5000ms
    
    
    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
    
    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
    注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
    注意:主类的名字必须是:Main,否则按无效代码处理。
    import java.util.Scanner;
    
    public class Main {
        
        /*
         * 这题的重点在于题意的理解,题意理解了,解答就会很简单
         *核心: 如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)
         * 递增排序后能得到一个长度为R-L+1的“连续”数列,则称这个区间连号区间。
         * 那么就是说,在给定的一个全排列中A[L]~A[R]之间未排序,如果经过递增排序处理后
         * 发现,A[L]~A[R]之间的元素每次自增1,即为一个连号区间。
         */
        public static void main(String[] args) {
            Scanner in = new Scanner(System.in);
            int n = in.nextInt();  //输入全排列的规模
            int[] data = new int[n];
            for(int i = 0;i < n;i++)  //输入该全排列具体元素,易知每一个元素均布相等
                data[i] = in.nextInt();
            int count = 0;
            for(int i = 0;i < n;i++) {
                int max = data[i];  //从i开始到后续i~n之间每一个区间的初始最大值
                int min = data[i];  //从i开始到后续i~n之间每一个区间的初始最小值
                for(int j = i;j < n;j++) {
                    if(max < data[j])
                        max = data[j];
                    if(min > data[j])
                        min = data[j];
                    if(max - min == j - i) {  //此处判断就是相当于经过递增排序处理后,符合连号区间顶点
                        count++;
                    }
                }
            }
            System.out.println(count);
        }
    }
  • 相关阅读:
    Cocos2d-x 3.0 事件系统【转】
    cocos2d-x中false,setSwallowTouches,stopPropagation的区别
    类成员函数指针 ->*语法剖析
    cocos2d-lua 3.5 ios搭建步骤
    cocos2d-lua 3.5 android搭建步骤
    cocos2d-lua 3.5 android搭建常见错误
    结构体
    乒乓球(0)<P2003_1>
    不高兴的津津(0)<P2004_1>
    陶陶摘苹果(0)<P2005_1>
  • 原文地址:https://www.cnblogs.com/liuzhen1995/p/6611876.html
Copyright © 2011-2022 走看看