蓝桥杯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 = formatter.parse(curDatetime);





    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]) {

                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 boolean check() {

        int sum = 0;

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

        }

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

            System.out.print(oper[i]);

        }

        System.out.println();

        System.out.println(sum);

        if (sum != 2015) {

            return false;

        } else {

            return true;

        }









    }





    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) {

    if(cur==13){

        if(sum==13){

            ans++;

            return;





        }

    }





    else{

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

            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

发布了19 篇原创文章 · 获赞 7 · 访问量 9914

猜你喜欢

转载自blog.csdn.net/weixin_42297075/article/details/104025899