第十一届蓝桥杯大赛软件赛省赛_Java_B组

第十一届蓝桥杯大赛软件赛省赛_Java_B组

试题A:解密(5分)

在这里插入图片描述

分析

这是一道结果填空题,直接对照着加密表改回去就行了

参考答案
YeRikGSunlRzgDlvRwYkXkrGgghXaA

试题B:纪念日(5分)

在这里插入图片描述

分析

这是一道结果填空题,但是直接手算有点麻烦,使用Java里面的Date类进行辅助计算即可

参考代码
public class QuestionB {
	public static void main(String[] args) throws Exception {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd mm:HH:ss");
		Date start = sdf.parse("1921-7-23 12:00:00");
		Date end = sdf.parse("2020-7-1 12:00:00");
		long startTime = start.getTime();
		long endTime = end.getTime();
        // 两个日期之间的秒差
		System.out.println(endTime - startTime);
        // 分钟差
		System.out.println((endTime - startTime) / 60);
	}
}

试题C:合并检测(10分)

分析

这是一道结果填空题,这道题挺奇怪的

按照题目意思,设定A国总人数为n,按照感染率来算

阳的人数:n/100

阴的人数:99n/100

则需要 99n / 100 + ( k + 1 ) * n / 100,即n / k + n / 100

到这一步,就不知道怎么写了

但是根据我们平时做核酸来看,一管是10个人,那么这道题实在不会的话,填10就行了

答案也确实是10😂

参考答案
10

试题D:分配口罩(10分)

在这里插入图片描述

分析

这也是一道结果填空题

这道题有三种思路可以做

手算(不推荐)

因为是结果填空题,如果你有耐心的话,一个个凑着试一试吧

回溯

直接列举所有的可能性,然后取最小的那一种就行了

转化为01背包

这道题目和力扣1049题:最后一块石头的重量Ⅱ有点类似

本质就是01背包问题

参考代码
回溯

PS:会很慢很慢很慢,可能跑几个小时都跑不完,至少得有 15! 种可能也就是1307674368000种可能

public class QuestionD {
    public static void main(String[] args) {
        int[] masks = { 9090400, 8499400, 5926800, 8547000, 4958200, 4422600, 5751200, 4175600, 6309600, 5865200,
                       6604400, 4635000, 10663400, 8087200, 4554000 };
        System.out.println(backTrack(masks));
    }
    static long min;
    private static long backTrack(int[] masks) {
        min = Integer.MAX_VALUE;
        LinkedList<Integer> track = new LinkedList<>();
        boolean[] choose = new boolean[masks.length];
        backTrack(track, masks, choose);
        return min;
    }

    private static void backTrack(LinkedList<Integer> track, int[] masks, boolean[] choose) {
        if (track.size() == masks.length) {
            return;
        }
        // 更新最小值
        min = Math.min(Math.abs(sum(track) - sumUnChoose(masks, choose)), min);
        System.out.println(min);
        for (int i = 0; i < masks.length; i++) {
            if (choose[i]) {
                continue;
            }
            track.addLast(masks[i]);
            choose[i] = true;
            backTrack(track, masks, choose);
            track.removeLast();
            choose[i] = false;
        }
    }

    private static long sum(LinkedList<Integer> track) {
        return track.stream().reduce(0, Integer::sum);
    }

    private static long sumUnChoose(int[] masks, boolean[] choose) {
        long sum = 0;
        for (int i = 0; i < choose.length; i++) {
            if (!choose[i]) {
                sum += masks[i];
            }
        }
        return sum;
    }
}
01背包
public class QuestionD {
	public static void main(String[] args) {
		int[] masks = { 9090400, 8499400, 5926800, 8547000, 4958200, 4422600, 5751200, 4175600, 6309600, 5865200,
				6604400, 4635000, 10663400, 8087200, 4554000 };
		int sum = 0;
		for (int i = 0; i < masks.length; i++) {
			sum += masks[i];
		}
		long oneMax = zeroOneBag(masks, sum / 2);
		long twoMax = sum - oneMax;
		System.out.println(twoMax - oneMax);
	}

	private static long zeroOneBag(int[] masks, int target) {
		// dp[j]:容量为j的背包用所有的物品最多可以装dp[j]
		long[] dp = new long[target + 1];
		// 遍历物品
		for (int i = 0; i < masks.length; i++) {
			// 遍历背包
			for (int j = target; j >= masks[i]; j--) {
				// 装和不装取一个最大的
				dp[j] = Math.max(dp[j], dp[j - masks[i]] + masks[i]);
			}
		}
		return dp[target];
	}
}

试题E:斐波那契数列最大公约数(15分)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sNOw7oUL-1692525444479)(第十一届蓝桥杯大赛软件赛省赛_Java_B组/image-20230318213110583.png)]

分析

这是一道结果填空题,但是如果想通过手算得到结果,那是不可能的

下面考虑两个问题

1、如何计算F2020和F520

因为F2020的数值非常非常大,F520的数量级也不可小觑

首先来考虑一下如何计算斐波那契数列指定位置的值,如果使用递归来计算F2020的话,估计几个小时都计算不到2020的值

斐波那契数列除了递归计算,还有一种优化算法就是使用动态规划的思想来计算,状态转移方程都已经有了

这样就可以快速得出指定位置的斐波那契数

这里要注意一点,就是因为F2020数量级过于巨大,如果使用int甚至long都会产生溢出,所以要使用BigInteger或者BigDemical来计算

2、如何计算两个数的最大公约数

这个记住代码就行了

ab的公约数记作gcb(a,b)

static BigDecimal gcb(BigDecimal x, BigDecimal y) {
	return x.remainder(y).intValue() == 0 ? y : gcb(y, x.remainder(y));
}
参考代码
public class QuestionE {
	public static void main(String[] args) {
		BigDecimal[] dp = new BigDecimal[2021];
		dp[1] = new BigDecimal("1");
		dp[2] = new BigDecimal("1");
		for (int i = 3; i < 2021; i++) {
			dp[i] = dp[i - 1].add(dp[i - 2]);
		}
		System.out.println(gcb(dp[2020], dp[520]));
	}

	static BigDecimal gcb(BigDecimal x, BigDecimal y) {
		return x.remainder(y).intValue() == 0 ? y : gcb(y, x.remainder(y));
	}
}

试题F:分类计数(15分)

在这里插入图片描述

分析

这个很简单,直接计数即可

参考代码
public class QuestionF {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String input = sc.nextLine();
		int[] bucket = new int[3];
		char[] iArray = input.toCharArray();
		for (int i = 0; i < iArray.length; i++) {
			char t = iArray[i];
			if (t >= 'A' && t <= 'Z') {
				bucket[0]++;
			} else if (t >= 'a' && t <= 'z') {
				bucket[1]++;
			} else if (t >= '0' && t <= '9') {
				bucket[2]++;
			}
		}
		System.out.println(bucket[0]);
		System.out.println(bucket[1]);
		System.out.println(bucket[2]);
	}
}

试题G:八次求和(20分)

分析

题目意思很好理解

这道题难就难在 n 的数值会很大,导致 n 的8次方很大

在这里插入图片描述

举个栗子

(15 * 15 * 15 * 15) % 4可以被拆为(12 * 15 * 15 * 15) % 4 + (3 * 15 * 15 * 15) % 4

左边那个(12 * 15 * 15 * 15) % 4 最后的结果肯定是0,所以只需要计算右边的值(3 * 15 * 15 * 15) % 4

同理就变成了(3 * 3 * 3 * 3) % 4

15 ^ 450625

3 ^ 481

参考代码
public class QuestionG {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();
		long result = 0;
		for (int counter = 1; counter <= n; counter++) {
			long temp = 1;
			for (int i = 0; i < 8; i++) {
                // 累计计算
				temp = (temp * counter) % 123456789L;
			}
            // 将结果直接取余
			result = (result + temp) % 123456789L;
		}
		System.out.println(result);
	}
}

试题H:字符串编码(20分)

在这里插入图片描述

分析

使用回溯算法将所有的可能列举出来,在其中取得字典序最大的那种选择即可

参考代码

public class QuestionH {

    static int max;
    static String result;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        char[] sArray = scanner.nextLine().toCharArray();
        System.out.println(backtrack(sArray));
    }

    private static String backtrack(char[] sArray) {
        max = Integer.MIN_VALUE;
        Map<Integer, Character> dictionary = dictionary();
        LinkedList<Character> track = new LinkedList<>();
        backtrack(sArray, track, dictionary, 0);
        return result;
    }

    private static void backtrack(char[] sArray, LinkedList<Character> track, Map<Integer, Character> dictionary, int index) {
        if (index == sArray.length) {
            updateResult(track);
            return;
        }
        char cur = sArray[index];
        // 做出第一次选择
        track.addLast(dictionary.get(spell(sArray, index, index)));
        backtrack(sArray, track, dictionary, index + 1);
        track.removeLast();
        if (cur != '1' && cur != '2') {
            return;
        }
        // 可以再追加一次选择
        if (index + 1 < sArray.length) {
            track.addLast(dictionary.get(spell(sArray, index, index + 1)));
            backtrack(sArray, track, dictionary, index + 2);
            track.removeLast();
        }
    }

    /**
     * 将sArray的[i,j]区间的字符拼起来转化为数字返回
     *
     * @param sArray
     * @param i
     * @param j
     * @return
     */
    private static int spell(char[] sArray, int i, int j) {
        int sum = 0;
        int base = 1;
        // 将sArray的i和j放一块返回数值
        for (int k = j; k >= i; k--) {
            sum += base * (sArray[k] - '0');
            base *= 10;
        }
        return sum;
    }

    /**
     * 根据当前路径生成组成的字符串,并判断是否需要更新最大值
     *
     * @param track
     */
    private static void updateResult(LinkedList<Character> track) {
        int sum = 0;
        StringBuilder sBuilder = new StringBuilder();
        for (int i = 0; i < track.size(); i++) {
            char cur = track.get(i);
            sum += cur;
            sBuilder.append(cur);
        }
        // 字典序更大的话,更新此次路径
        if (sum > max) {
            result = sBuilder.toString();
        }
    }

    /**
     * 创建一个字典
     * key是数字
     * value是对应的字符
     *
     * @return
     */
    private static Map<Integer, Character> dictionary() {
        Map<Integer, Character> map = new HashMap<>(32);
        for (int i = 1; i <= 26; i++) {
            map.put(i, (char) ('A' + i - 1));
        }
        return map;
    }
}

试题I:BST插入问题(25分)

在这里插入图片描述

试题J:网络分析(25分)

在这里插入图片描述

分析

首先要理解题目意思,然后就是普通的将图构造出来,然后根据多个类型的操作对图进行添加节点之间的连接和遍历操作

参考代码
public class QuestionJ {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        LinkedList<int[]> operations = new LinkedList<>();
        for (int i = 0; i < m; i++) {
            operations.add(new int[]{scanner.nextInt(), scanner.nextInt(), scanner.nextInt()});
        }
        // 记录每个节点的累计信息值
        int[] nodes = new int[n + 1];
        LinkedList<Integer>[] graph = new LinkedList[n + 1];
        for (int i = 0; i < graph.length; i++) {
            graph[i] = new LinkedList<>();
        }
        for (Iterator iterator = operations.iterator(); iterator.hasNext(); ) {
            int[] is = (int[]) iterator.next();
            // 判断操作类型
            if (is[0] == 1) {
                // 建立连接
                graph[is[1]].add(is[2]);
                graph[is[2]].add(is[1]);
            } else {
                // 传播信息,发送方和接收方都需要添加
                nodes[is[1]] += is[2];
                traverse(graph, is[1], is[2], new boolean[n + 1], nodes);
            }
        }
        System.out.println(Arrays.toString(nodes));
    }

    private static void traverse(LinkedList<Integer>[] graph, int sequence, int t, boolean[] visisted, int[] nodes) {
        visisted[sequence] = true;
        for (int neighbor : graph[sequence]) {
            // 如果邻居已经访问过了,就不需要访问了
            if (visisted[neighbor]) {
                continue;
            }
            nodes[neighbor] += t;
            traverse(graph, neighbor, t, visisted, nodes);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝麻\n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值