蓝桥杯javaA组2015省赛题解

熊怪吃核桃

 

1.森林里有一只熊怪,很爱吃核桃。不过它有个习惯,每次都把找到的核桃分成相等的两份,吃掉一份,留一份。如果不能等分,熊怪就会扔掉一个核桃再分。第二天再继续这个过程,直到最后剩一个核桃了,直接丢掉。

有一天,熊怪发现了1543个核桃,请问,它在吃这些核桃的过程中,一共要丢掉多少个核桃。

请填写该数字(一个整数),不要填写任何多余的内容或说明文字。

思路:

1.57

模拟题,直接按照思路模拟即可。


 

public static void main(String[] args) {

    int num=1543;

    int count=0;

    while(num!=1){

        if(num%2==0){

            num=num/2;

        }

        else{

            num--;

            num=num/2;

            count++;

        }

    }

    System.out.println(count+1);

}

2.星系炸弹

 

在X星系的广袤空间中漂浮着许多X星人造“炸弹”,用来作为宇宙中的路标。

每个炸弹都可以设定多少天之后爆炸。

比如:阿尔法炸弹2015年1月1日放置,定时为15天,则它在2015年1月16日爆炸。

有一个贝塔炸弹,2014年11月9日放置,定时为1000天,请你计算它爆炸的准确日期。

 

请填写该日期,格式为 yyyy-mm-dd  即4位年份2位月份2位日期。比如:2015-02-19

请严格按照格式书写。不能出现其它文字或符号。

 

思路:

要么是使用date类,要么就是自己写函数

实际上要用到date和calendar

public static void main(String[] args) throws ParseException {

    //设置日期格式
    DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

    String curDatetime = "2014-11-09";
    //转换为date对象
    Date date = formatter.parse(curDatetime);
    //转换为calendar对象
    Calendar calendar = Calendar.getInstance();
    //设置时间
    calendar.setTime(date);
    //添加日期
    calendar.add(Calendar.DATE,1000);
    //转换为字符串形式

    String datetime = formatter.format(calendar.getTime());

    System.out.println(datetime);

}

3.九数分三组

 

1~9的数字可以组成3个3位数,设为:A,B,C,  现在要求满足如下关系:

B = 2 * A

C = 3 * A

 

请你写出A的所有可能答案,数字间用空格分开,数字按升序排列。

 

注意:只提交A的值,严格按照格式要求输出。

 

思路:

要么是暴力求解 for循环, 要么是dfs

使用dfs

public class q201503 {

    static int[] nums = new int[9];

    static boolean[] vis = new boolean[9];

    static int count = 0;

    static ArrayList<Integer> out = new ArrayList<Integer>();





    public static void dfs(int flag) {

        if (flag == 9) {

            int[] res = new int[3];

            for (int i = 0; i < 3; i++) {
            //将九个数字组成三个三位数

                res[i] = 100 * nums[i * 3] + 10 * nums[i * 3 + 1] + nums[i * 3 + 2];

            }

            int sum = 0;

            if (res[1] == 2 * res[0] && res[2] == 3 * res[0]) {
            //满足条件
            //把A添加到输出数组中

                out.add(res[0]);

            }

            count++;

            return;

        }

        for (int i = 0; i < 9; i++) {

            if (vis[i] == false) {

                nums[flag] = i + 1;

                vis[i] = true;

                dfs(flag + 1);

                vis[i] = false;

            }

        }

    }

    public static void main(String[] args) {

        dfs(0);
        //排序

        Collections.sort(out);

        for (int num:

             out) {

            System.out.print(num+" ");

        }

    }



4.

循环节长度

两个整数做除法,有时会产生循环小数,其循环部分称为:循环节。

比如,11/13=6=>0.846153846153.....  其循环节为[846153] 共有6位。

下面的方法,可以求出循环节的长度。

 

请仔细阅读代码,并填写划线部分缺少的代码。

   public static int f(int n, int m)

    {

        n = n % m;    

        Vector v = new Vector();

        

        for(;;)

        {

            v.add(n);

            n *= 10;

            n = n % m;

            if(n==0) return 0;

            if(v.indexOf(n)>=0)  _________________________________ ;  //填空

        }

    }

 

注意,只能填写缺少的部分,不要重复抄写已有代码。不要填写任何多余的文字。

思路:

暂时不会

其实理解了就很简单了。循环进行计算并吧计算结果加入vector中,当一个计算结果与vector储存的结果一致的时候,说明已经进入循环,返回此时的大小即为循环节长度。

v.size()

 

5.打印菱形

 

给出菱形的边长,在控制台上打印出一个菱形来。

为了便于比对空格,我们把空格用句点代替。

当边长为8时,菱形为:

.......*

......*.*

.....*...*

....*.....*

...*.......*

..*.........*

.*...........*

*.............*

.*...........*

..*.........*

...*.......*

....*.....*

.....*...*

......*.*

.......*

 

下面的程序实现了这个功能,但想法有点奇怪。

请仔细分析代码,并填写划线部分缺失的代码。

 

public class A

{

    public static void f(int n)

    {

        String s = "*";

        for(int i=0; i<2*n-3; i++) s += ".";

        s += "*";

    

        String s1 = s + "\n";

        String s2 = "";

        

        for(int i=0; i<n-1; i++){

            //System.out.println("=>"+s);

            s = "." + _____________________________________ + "*";  //填空

            s1 = s + "\n" + s1;

            s2 += s + "\n";

        }

        System.out.println(s1+s2);        

    }

    

    public static void main(String[] args)

    {

        f(8);

    }

}

注意,只能填写缺少的部分,不要重复抄写已有代码。不要填写任何多余的文字。

 

思路:

暂时只能试

s.substring(0, 2 * n - 4 - i)

试了这么久才试出来。一开始要先调试看看有什么规律,善于使用调试

 

6.加法变乘法

 

我们都知道:1+2+3+ ... + 49 = 1225

现在要求你把其中两个不相邻的加号变成乘号,使得结果为2015

 

比如:

1+2+3+...+10*11+12+...+27*28+29+...+49 = 2015

就是符合要求的答案。

 

请你寻找另外一个可能的答案,并把位置靠前的那个乘号左边的数字提交(对于示例,就是提交10)。

 

注意:需要你提交的是一个整数,不要填写任何多余的内容。

 

思路:

目测是用dfs搜索了,填空题 暴力循环也可以

忽略了一个是不相邻的加号

public class q201506 {

    static int[] num = new int[50];

    static int[] oper = new int[50];

    static int count = 0;

    public static void dfs(int flag) {

        if (flag == 49 || count == 2) {

            int sum = 0;
            //确定两个乘号的位置

            int[] op=new int[2];

            int index=0;

            for (int i = 1; i < 50; i++) {

                if (oper[i] == 1) {

                    op[index] = i;

                    index++;

                }

            }
            //乘法先计算

            sum+=op[0]*(op[0]+1)+op[1]*(op[1]+1);

            for (int i = 1; i <50 ; i++) {
                //不是乘号的位置则相加

                if(i!=op[0]&&i!=op[1]&&i!=op[0]+1&&i!=op[1]+1){

                    sum+=i;

                }

            }

            //System.out.println(sum);

            if (sum == 2015) {
                   //打印第一个乘号的位置

                System.out.println(op[0]);

            }

            return;

        }

        for (int i = 1; i < 50; i++) {

            if (oper[i] == 0 && oper[i - 1] != 1) {
                //确保不是相邻两个加号

                oper[i] = 1;

                count++;

                dfs(i + 1);

                count--;

                oper[i] = 0;

            }

        }
    }

    public static void main(String[] args) {

        dfs(1);

    }

}

写了很久终于写出来了,主要是两个难点 如何将不相邻的加号换成乘以及如何将结果进行结算

其实for循环也不是不可以。但是使用dfs可读性好一点。性能会不会好一些。

 

7.牌型种数

 

小明被劫持到X赌城,被迫与其他3人玩牌。

一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。

这时,小明脑子里突然冒出一个问题:

如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?

 

请填写该整数,不要填写任何多余的内容或说明文字。

思路:

dfs

不考虑花色 会有四张同样的数字

不考虑顺序,那就是只要按小到大

20分钟没做对

去年的代码:

思路是用数组存储13种牌剩余的数量,即remain[i]表示点数为i的牌剩余的数量, 

 static int[] pos=new int[13];

    static int[] remain=new int[13];

    static  int cnt=0;

    static void dfs(int cur){

        if(cur==13){

            cnt++;

            return;

        }

        for(int i=0;i<13;i++){

            if(remain[i]>-4){

            remain[i]--;

            pos[cur]=i;

            if(cur!=0){

                if(pos[cur]>=pos[cur-1]){//不考虑顺序,所以只需把升序的结果计算出来即可

                    dfs(cur+1);

                }

            }

            else {

                dfs(cur+1);

            }





            remain[i]++;

            pos[cur]--;}



        }

    }

    public static void main(String[] args){

        dfs(0);

        System.out.println(cnt);//变成全排列了,


    }

参考网络上的写法,没有使用数组储存,顺序搜索13种牌,每种牌有0-4张,凑够13张就算是一种结果输出。

//当前排列的总张数
static int sum = 0;
//答案数
static int ans = 0;

public static void cal(int cur) {
//cur表示当前搜索到第cur种牌

    if(cur==13){
//全部牌都搜索完,且总张数为13,则结果加一

        if(sum==13){

            ans++;

            return;
        }

    }

    else{

        for (int i = 0; i <5 ; i++) {
            //0-4,表示当前种类的牌数可以为0张到4张

            sum+=i;

            cal(cur+1);

            sum-=i;
        }

    }

}

public static void main(String[] args) {

    cal(0);

    System.out.println(ans);

}

8.移动距离

 

X星球居民小区的楼房全是一样的,并且按矩阵样式排列。其楼房的编号为1,2,3...

当排满一行时,从下一行相邻的楼往反方向排号。(蛇形走位)

比如:当小区排号宽度为6时,开始情形如下:

 

1  2  3  4  5  6

12 11 10 9  8  7

13 14 15 .....

 

我们的问题是:已知了两个楼号m和n,需要求出它们之间的最短移动距离(不能斜线方向移动)

 

输入为3个整数w m n,空格分开,都在1到10000范围内

w为排号宽度,m,n为待计算的楼号。

要求输出一个整数,表示m n 两楼间最短移动距离。

 

例如:

用户输入:

6 8 2

则,程序应该输出:

4

 

再例如:

用户输入:

4 7 20

则,程序应该输出:

5

思路:

先把蛇形走位的矩阵坐标转换成正常的坐标,然后使用dp进行计算即可。其实还用不上dp,只能走直线的话,直接x+y相加即可。        

public static void main(String[] args) {

    Scanner s=new Scanner(System.in);

    int w=s.nextInt();

    int m=s.nextInt();

    int n=s.nextInt();

    int x_m;

    int x_n;

    int y_n=n%w==0?n/w-1:n/w;//能整除的要减一

    int y_m=m%w==0?m/w-1:m/w;

    if((y_m)%2==0){

        //偶数行

        x_m=m%w-1;

    }

    else{

        x_m=w-m%w;

    }

    if((y_n)%2==0){

        //偶数行

        x_n=n%w-1;

    }

    else{

        x_n=w-n%w;

    }

    System.out.println(Math.abs(x_m-x_n)+Math.abs(y_m-y_n));





}

 

9.垒骰子

 

赌圣atm晚年迷恋上了垒骰子,就是把骰子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。

经过长期观察,atm 发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!

我们先来规范一下骰子:1 的对面是 4,2 的对面是 5,3 的对面是 6。

假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来。 atm想计算一下有多少种不同的可能的垒骰子方式。

两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同。

由于方案数可能过多,请输出模 10^9 + 7 的结果。

 

不要小看了 atm 的骰子数量哦~

 

「输入格式」

第一行两个整数 n m

n表示骰子数目

接下来 m 行,每行两个整数 a b ,表示 a 和 b 不能紧贴在一起。

 

「输出格式」

一行一个数,表示答案模 10^9 + 7 的结果。

 

「样例输入」

2 1

1 2

 

「样例输出」

544

思路:

暂时不会

public static void main(String[] args) {

    Scanner input = new Scanner(System.in);

    int n = input.nextInt();

    int m = input.nextInt();

    int[][] A = new int[6][6];

    //初始化矩阵

    for (int i = 0; i < A.length; i++) {

        for (int j = 0; j < A[0].length; j++) {

            A[i][j] = 1;

        }

    }

    int a, b;

    for (int i = 0; i < m; i++) {

        a = input.nextInt();

        b = input.nextInt();

        A[a - 1][b - 1] = 0;

        A[b - 1][a - 1] = 0;

    }

    int[] original = new int[6];

    Arrays.fill(original, 1);//直接填充





    int[][] temp = quickMatrix(A, n - 1);

    int[] res = matrix(temp, original);

    int sum = 0;

    for (int i = 0; i < 6; i++) {

        sum += res[i];

    }

    double t = Math.pow(4, n) * sum % 1000000007;

    System.out.println((int) t);

}





public static int[][] quickMatrix(int[][] A, int n) {

    if (n == 1) {

        return A;

    }

    if (n % 2 == 1) {

        return matrix(quickMatrix(A, n - 1), A);

    } else {

        int[][] temp = quickMatrix(A, n / 2);

        return matrix(temp, temp);

    }

}





public static int[][] matrix(int[][] A, int[][] B) {

    //dp

    int[][] res = new int[A.length][A[0].length];

    for (int i = 0; i < A.length; i++) {

        for (int j = 0; j < B[0].length; j++) {

            for (int k = 0; k < B.length; k++) {

                res[i][j] = res[i][j] + A[i][k] * B[k][j];

            }

        }

    }

    return res;

}





public static int[] matrix(int[][] A, int[] B) {

    int[] res = new int[B.length];

    for (int i = 0; i < A.length; i++) {

        for (int k = 0; k < B.length; k++) {

            res[i] = res[i] + A[i][k] * B[k];

        }

    }

    return res;

}

提到了一个知识点矩阵快速幂

 

10.灾后重建

 

Pear市一共有N(<=50000)个居民点,居民点之间有M(<=200000)条双向道路相连。这些居民点两两之间都可以通过双向道路到达。这种情况一直持续到最近,一次严重的地震毁坏了全部M条道路。

震后,Pear打算修复其中一些道路,修理第i条道路需要Pi的时间。不过,Pear并不打算让全部的点连通,而是选择一些标号特殊的点让他们连通。

Pear有Q(<=50000)次询问,每次询问,他会选择所有编号在[l,r]之间,并且 编号 mod K  = C 的点,修理一些路使得它们连通。由于所有道路的修理可以同时开工,所以完成修理的时间取决于花费时间最长的一条路,即涉及到的道路中Pi的最大值。

 

你能帮助Pear计算出每次询问时需要花费的最少时间么?这里询问是独立的,也就是上一个询问里的修理计划并没有付诸行动。

 

【输入格式】

第一行三个正整数N、M、Q,含义如题面所述。

接下来M行,每行三个正整数Xi、Yi、Pi,表示一条连接Xi和Yi的双向道路,修复需要Pi的时间。可能有自环,可能有重边。1<=Pi<=1000000。

 

接下来Q行,每行四个正整数Li、Ri、Ki、Ci,表示这次询问的点是[Li,Ri]区间中所有编号Mod Ki=Ci的点。保证参与询问的点至少有两个。

 

【输出格式】

输出Q行,每行一个正整数表示对应询问的答案。

 

【样例输入】

7 10 4

1 3 10

2 6 9

4 1 5

3 7 4

3 6 9

1 5 8

2 7 4

3 2 10

1 7 6

7 6 9

1 7 1 0

1 7 3 1

2 5 1 0

3 7 2 1

 

【样例输出】

9

6

8

8

 

【数据范围】

对于20%的数据,N,M,Q<=30

对于40%的数据,N,M,Q<=2000

对于100%的数据,N<=50000,M<=2*10^5,Q<=50000. Pi<=10^6. Li,Ri,Ki均在[1,N]范围内,Ci在[0,对应询问的Ki)范围内。

 

资源约定:

峰值内存消耗(含虚拟机) < 256M

CPU消耗  < 5000ms

 

 

请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

 

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。

注意:主类的名字必须是:Main,否则按无效代码处理。

思路:

太复杂了,估计比赛时候也写不出来,先不研究了。


 

//使用Prim算法,获取输入图的最小生成树

public int[][] getPrim(int[][] value) {

    int[][] result = new int[value.length][value[0].length]; //存放最终最小生成树的边权值

    int[] used = new int[value.length];  //用于判断顶点是否被遍历

    for (int i = 1, len = value.length; i < len; i++) {

        used[i] = -1;   //初始化,所有顶点均未被遍历

    }

    used[1] = 1;  //从顶点1开始遍历,表示顶点已经被遍历





    int count = 1;    //记录已经完成构造最小生成树的顶点

    int len = value.length;

    while (count < len) {  //当已经遍历的顶点个数达到图的顶点个数len时,退出循环

        int tempMax = Integer.MAX_VALUE;

        int tempi = 0;

        int tempj = 0;

        for (int i = 1; i < len; i++) {  //用于遍历已经构造的顶点

            if (used[i] == -1) {

                continue;

            }

            for (int j = 1; j < len; j++) {  //用于遍历未构造的顶点

                if (used[j] == -1) {

                    if (value[i][j] != 0 && tempMax > value[i][j]) {

                        tempMax = value[i][j];

                        tempi = i;

                        tempj = j;

                    }

                }

            }

        }

        result[tempi][tempj] = tempMax;

        result[tempj][tempi] = tempMax;

        used[tempj] = 1;

        count++;

    }

    return result;

}





//使用floyd算法获取所有顶点之间的最短路径的具体路径

public void floyd(int[][] primTree, int[][] path) {

    int[][] tree = new int[primTree.length][primTree.length];

    for (int i = 1; i < primTree.length; i++) {

        System.arraycopy(primTree[i], 1, tree[i], 1, primTree.length - 1);

    }

    for (int k = 1; k < primTree.length; k++) {

        for (int i = 1; i < primTree.length; i++) {

            for (int j = 1; j < primTree[0].length; j++) {

                if (tree[i][k] != 0 && tree[k][j] != 0) {

                    int temp = tree[i][k] + tree[k][j];

                    if (tree[i][j] == 0) {

                        tree[i][j] = temp;

                        path[i][j] = k;   //存放顶点i到顶点j之间的路径节点

                    }





                }

            }

        }

    }

}





//返回a与b之间的最大值

public int max(int a, int b) {

    return a > b ? a : b;

}





//根据最短路径,返回顶点start~end之间的最大权值边

public int dfsMax(int[][] primTree, int[][] path, int start, int end) {

    if (path[start][end] == 0) {

        return primTree[start][end];

    }

    int mid = path[start][end];  //start和end的中间顶点

    return max(dfsMax(primTree, path, start, mid), dfsMax(primTree, path, mid, end));

}





//根据最小生成树,返回各个顶点到其它顶点行走过程中,权值最大的一条边

public int[][] getMaxValue(int[][] primTree) {

    int[][] path = new int[primTree.length][primTree[0].length];

    floyd(primTree, path);       //获取具体最短路径

    int[][] result = new int[primTree.length][primTree[0].length];

    for (int i = 1; i < primTree.length; i++) {

        for (int j = 1; j < primTree.length; j++) {

            if (j == i) {

                continue;

            }

            int max = dfsMax(primTree, path, i, j);

            result[i][j] = max;

        }

    }

    return result;

}





//打印出题意结果

public void printResult(int[][] value, int[][] result) {

    int[][] primTree = getPrim(value);      //获取输入图的最小生成树

    int[][] maxResult = getMaxValue(primTree);    //获取各个顶点到其它顶点最短路径中最大权值边

    for (int i = 0; i < result.length; i++) {

        int L = result[i][0];

        int R = result[i][1];

        int K = result[i][2];

        int C = result[i][3];

        ArrayList<Integer> list = new ArrayList<Integer>();

        for (int j = L; j <= R; j++) {

            if (j % K == C) {

                list.add(j);

            }

        }

        int max = 0;

        for (int j = 0; j < list.size(); j++) {

            for (int k = j + 1; k < list.size(); k++) {

                if (max < maxResult[list.get(j)][list.get(k)]) {

                    max = maxResult[list.get(j)][list.get(k)];

                }

            }

        }

        System.out.println(max);

    }

    return;

}





public static void main(String[] args) {

    q201510 test = new q201510();

    Scanner in = new Scanner(System.in);

    int N = in.nextInt();

    int M = in.nextInt();

    int Q = in.nextInt();

    int[][] value = new int[N + 1][N + 1];

    for (int i = 1; i <= M; i++) {

        int a = in.nextInt();

        int b = in.nextInt();

        int tempV = in.nextInt();

        value[a][b] = tempV;

        value[b][a] = tempV;

    }

    int[][] result = new int[Q][4];

    for (int i = 0; i < Q; i++) {

        result[i][0] = in.nextInt();

        result[i][1] = in.nextInt();

        result[i][2] = in.nextInt();

        result[i][3] = in.nextInt();

    }

    test.printResult(value, result);

}



参考

https://blog.csdn.net/a1439775520/article/details/97646511

2022年蓝桥杯Java A是中国著名的计算机竞赛之一,该比赛旨在发掘和培养优秀的Java程序设计人才。参赛者需要具备一定的Java编程基础和算法思维能力,通过解决一系列实际问题来展示自己的技术水平。 蓝桥杯Java A比赛内容将涉及Java语言基础知识、面向对象编程、数据结构与算法、数据库等方面。参赛选手需要通过模拟真实的工作场景,设计和实现各种功能模块,展现出自己解决问题的能力和代码的优雅性。 蓝桥杯Java A比赛对于参赛者来说是一次难得的锻炼机会。通过参加比赛,可以学习到实际项目中常用的技术和解决问题的思路,提高自己的编程能力。同时,这也是一个展示自己才华和与其他选手竞争的舞台,可以通过与其他优秀选手的交流互动,拓宽自己的视野,并且与同龄人一起追求计算机编程的进步。 参加蓝桥杯Java A比赛,不仅可以提升自己的技术能力,还能为自己的未来发展增加一份宝贵的竞赛经验。很多优秀的程序员和企业都非常看重蓝桥杯的参赛者,因为这代表着他们在编程领域具备一定的实力和潜力。 总而言之,参加2022年蓝桥杯Java A是一个对自己实力的检验和提高的机会,同时也是一个与其他优秀选手竞争的平台,可以通过比赛锻炼自己的技术能力和解决问题的能力。参赛者在比赛中要保持冷静和耐心,学会与其他选手交流和合作,相信通过努力,一定能够在比赛中取得好的成绩。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值