2016年第七届蓝桥杯国赛试题及详解(Java本科B组)

1. 愤怒小鸟

愤怒小鸟

X星球愤怒的小鸟喜欢撞火车!

一根平直的铁轨上两火车间相距 1000 米
两火车 (不妨称A和B) 以时速 10米/秒 相对行驶。

愤怒的小鸟从A车出发,时速50米/秒,撞向B车,
然后返回去撞A车,再返回去撞B车,如此往复…
两火车在相距1米处停车。

问:这期间愤怒的小鸟撞 B 车多少次?

注意:需要提交的是一个整数(表示撞B车的次数),不要填写任何其它内容。

解析:

注意,这道题只能通过算时间来计算次数,按照距离来计算是错误的。
因为到两个车相距小于1m的时候,也会发生好几次碰撞

package A;

public class Main {
    public static void main(String[] args) {
        double ab = 1000;
        double t;
        int cnt = 0;
        while (ab > 1) {
            // 小鸟撞b车
            t = ab / 60;
            ab -= 20*t;
            cnt++;

            // 小鸟撞a车
            t = ab / 60;
            ab -= 20*t;
        }
        System.out.println(cnt);
    }
}

我的答案是:9

2. 反幻方

反幻方

我国古籍很早就记载着

2 9 4
7 5 3
6 1 8

这是一个三阶幻方。每行每列以及对角线上的数字相加都相等。

下面考虑一个相反的问题。
可不可以用 1~9 的数字填入九宫格。
使得:每行每列每个对角线上的数字和都互不相等呢?

这应该能做到。
比如:
9 1 2
8 4 3
7 5 6

你的任务是搜索所有的三阶反幻方。并统计出一共有多少种。
旋转或镜像算同一种。

比如:
9 1 2
8 4 3
7 5 6

7 8 9
5 4 1
6 3 2

2 1 9
3 4 8
6 5 7

等都算作同一种情况。

请提交三阶反幻方一共多少种。这是一个整数,不要填写任何多余内容。

解析:

这是一道比较常规的搜索题,将所有答案暴力搜索出来后,判断行列对角线是否不相等,统计数量。
最后注意要除8

package B;

import java.util.ArrayList;
import java.util.HashSet;

public class Main {
    static int cnt = 0;
    static int[] vis = new int[15];
    static int[] arr = new int[15];
    static HashSet<ArrayList<Integer>> s = new HashSet<>();
    static boolean judge() {
        HashSet<Integer> set = new HashSet<>();
        int r1 = arr[0] + arr[1] + arr[2];
        int r2 = arr[3] + arr[4] + arr[5];
        int r3 = arr[6] + arr[7] + arr[8];
        
        int c1 = arr[0] + arr[3] + arr[6];
        int c2 = arr[1] + arr[4] + arr[7];
        int c3 = arr[2] + arr[5] + arr[8];
        
        int d1 = arr[0] + arr[4] + arr[8];
        int d2 = arr[2] + arr[4] + arr[6];
        set.add(r1);
        set.add(r2);
        set.add(r3);
        
        set.add(c1);
        set.add(c2);
        set.add(c3);
        
        set.add(d1);
        set.add(d2);
        if (set.size() == 8) {
            return true;
        } 
        return false;
    }
    
    static void dfs(int n) {
        if (n == 9) {
            if (judge()) {
                cnt++;
            }
            return ;
        }
        
        for (int i = 1; i <= 9; i++) {
            if (vis[i] == 0) {
                vis[i] = 1;
                arr[n] = i;
                dfs(n+1);
                vis[i] = 0;
            }
        }
    }
    public static void main(String[] args) {
        dfs(0);
        System.out.println(cnt / 8);
    }
}

我的答案是:3120

3. 打靶

代码填空题,仔细分析下递归,一般这种填空题都要用到三目运算符。
我的答案是:ho - (i == 0 ? 0 : 1)

4. 路径之谜

小明冒充X星球的骑士,进入了一个奇怪的城堡。
城堡里边什么都没有,只有方形石头铺成的地面。

假设城堡地面是 n x n 个方格。【如图1.png】所示。

按习俗,骑士要从西北角走到东南角。
可以横向或纵向移动,但不能斜着走,也不能跳跃。
每走到一个新方格,就要向正北方和正西方各射一箭。
(城堡的西墙和北墙内各有 n 个靶子)

同一个方格只允许经过一次。但不必做完所有的方格。

如果只给出靶子上箭的数目,你能推断出骑士的行走路线吗?
在这里插入图片描述
有时是可以的,比如图1.png中的例子。

本题的要求就是已知箭靶数字,求骑士的行走路径(测试数据保证路径唯一)

输入:
第一行一个整数N(0<N<20),表示地面有 N x N 个方格
第二行N个整数,空格分开,表示北边的箭靶上的数字(自西向东)
第三行N个整数,空格分开,表示西边的箭靶上的数字(自北向南)

输出:
一行若干个整数,表示骑士路径。

为了方便表示,我们约定每个小格子用一个数字代表,从西北角开始编号: 0,1,2,3…
比如,图1.png中的方块编号为:

0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15

示例:
用户输入:
4
2 4 3 4
4 3 3 3

程序应该输出:
0 4 5 1 2 3 7 11 10 9 13 14 15

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms

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

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

解析:

这是道搜索题,但考的还比较细致。
需要搜索的时候剪支,然后也要记录路径

package D;

import java.util.Scanner;

public class Main {
    static int[][] G = new int[25][25];
    static boolean[][] vis = new boolean[25][25];
    static int N;
    static int[] p = {0, 0, -1, 1}, q = {1, -1, 0, 0};
    static int[] north = new int[25];
    static int[] west = new int[25];
    
    static int[] row = new int[25];
    static int[] col = new int[25];
    
    static int[] num = new int[500];
    static boolean judge(int x, int y) {
        if (x >= 0 && x < N && y >= 0 && y < N && vis[x][y] == false) {
            return true;
        }
        return false;
    }
    
    static void print(int step) {
        for (int i = 0; i < step; i++) {
            System.out.print(num[i] + " ");
        }
        System.out.println();
    }
    
    static void dfs(int x, int y, int step) {
        if (row[x] > west[x] || col[y] > north[y]) return ;
        if (x == N-1 && y == N-1) {
            for (int i = 0; i < N; i++) {
                if (row[i] != west[i] || col[i] != north[i])
                    return ;
            }
            print(step);
            return ;
        }
        
        for (int i = 0; i < 4; i++) {
            int nx = x + p[i];
            int ny = y + q[i];
            if (judge(nx, ny)) {
                num[step] = G[nx][ny];
                row[nx]++;
                col[ny]++;
                vis[nx][ny] = true;
                dfs(nx, ny, step+1);
                row[nx]--;
                col[ny]--;
                vis[nx][ny] = false;
            }
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        for (int i = 0; i < N; i++) {
            north[i] = sc.nextInt();
        }
        for (int i = 0; i < N; i++) {
            west[i] = sc.nextInt();
        }
        int cnt = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                G[i][j] = cnt++;
                vis[i][j] = false;
            }
        }
        row[0]++;
        col[0]++;
        vis[0][0] = true;
        num[0] = 0;
        dfs(0, 0, 1);
    }
}

5. 碱基

生物学家正在对n个物种进行研究。
其中第i个物种的DNA序列为s[i],其中的第j个碱基为s[i][j],碱基一定是A、T、G、C之一。
生物学家想找到这些生物中一部分生物的一些共性,他们现在关注那些至少在m个生物中出现的长度为k的连续碱基序列。准确的说,科学家关心的序列用2m元组(i1,p1,i2,p2…im,pm)表示,
满足:
1<=i1<i2<…<im<=n;
且对于所有q(0<=q<k), s[i1][p1+q]=s[i2][p2+q]=....=s[im][pm+q]。

现在给定所有生物的DNA序列,请告诉科学家有多少的2m元组是需要关注的。如果两个2m元组有任何一个位置不同,则认为是不同的元组。

【输入格式】
输入的第一行包含三个整数n、m、k,两个整数之间用一个空格分隔,意义如题目所述。
接下来n行,每行一个字符串表示一种生物的DNA序列。
DNA序列从1至n编号,每个序列中的碱基从1开始依次编号,不同的生物的DNA序列长度可能不同。

【输出格式】
输出一个整数,表示关注的元组个数。
答案可能很大,你需要输出答案除以1000000007的余数。

【样例输入】
3 2 2
ATC
TCG
ACG

【样例输出】
2

再例如:
【样例输入】
4 3 3
AAA
AAAA
AAA
AAA

【样例输出】
7

【数据规模与约定】
对于20%的数据,k<=5,所有字符串总长L满足L <=100
对于30%的数据,L<=10000
对于60%的数据,L<=30000
对于100%的数据,n<=5,m<=5,1<=k<=L<=100000
保证所有DNA序列不为空且只会包含’A’ ’G’ ’C’ ’T’四种字母

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms

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

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

解析:

这是一道阅读题,读懂题意就简单了。
题目意思就是在n个物种里选m个,然后这m个物种呢,都有相同的长度为k的子串

然后问你有多少种子串组合方式。

例如样例2.
首先有4个物种,在4个里面挑3个
{1, 2, 3}, {1, 2, 4}, {1, 3, 4}, {2, 3, 4}四种组合方式

然后组合方式中找子串相同的情况有多少种。
{1, 2, 3}是两种
{1, 2, 4}也是两种
{2, 3, 4}也是两种
{1, 3, 4}是一种,加起来就是七种

因为n和m比较小,所以可以枚举出所有组合。
然后再选取第一个序列,暴力枚举出所有长度为k的子串,找这些子串在后序序列中的个数,相乘就能得到答案

package E;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main {
    static InputReader in = new InputReader(new BufferedInputStream(System.in));
    static PrintWriter out = new PrintWriter(System.out);
    static String[] jianji = new String[15];
    static int[] arr = new int[15]; 
    static boolean[] vis = new boolean[15];
    static int n, m, k, sum = 0;
    
    static int find(String a, String b) {
        // a中有多少个b子串
        int k = -1;
        int cnt = -1;
        while (k != 0) {
            k = a.indexOf(b, k) + 1;
            cnt++;
        }
        return cnt;
    }
    
    // n个数选m个。
    static void dfs(int cnt) {
        if (cnt == m+1) {
            String s = jianji[arr[1]];
            for (int i = 0; k+i <= s.length(); i++) {
                String sub = s.substring(i, k+i);
                int t = 1;
                for (int j = 2; j <= m; j++) {
                    // 看后序序列中包含了多少个s子串
                    t = (t * find(jianji[arr[j]], sub)) % 1000000007;
                }
                sum = (sum + t) % 1000000007;
            }
            return ;
        }
        
        // 从上一个数+1开始取
        for (int q = arr[cnt-1] + 1; q <= n; q++) {
            if (vis[q] == false) {
                vis[q] = true;
                arr[cnt] = q;
                dfs(cnt+1);
                vis[q] = false;
            }
        }
    }
    
    public static void main(String[] args) {
        n = in.nextInt();
        m = in.nextInt();
        k = in.nextInt();
        for (int i = 1; i <= n; i++) {
            jianji[i] = in.readLine();
        }
        dfs(1);
        // 枚举所有情况
        out.println(sum);
        out.flush();
        out.close();
    }
    
    public static class InputReader {
        public static BufferedReader br;
        public static StringTokenizer st;
        
        public InputReader(InputStream stream) {
            br = new BufferedReader(new InputStreamReader(stream), 32768);
            st = null;
        }
        
        public String next() {
            while(st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }
        
        public String readLine() {
            String s = null;
            try {
                s = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return s;
        }
        
        public int nextInt() {
            return Integer.parseInt(next());
        }
        
        public Long nextLong() {
            return Long.parseLong(next());
        }
        
        public Double nextDoule() {
            return Double.parseDouble(next());
        }
    }
}

6. 圆圈舞

待更新。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值