蓝桥杯第十一届校赛模拟赛(Java)

在这里插入图片描述

敲黑板!!!重点重点!!!学计算机你连这个都记不住,丢你男朋友的脸(没有男朋友的当我没有说)

  1. 1KB=1024B=2^10B
  2. 1MB=1024KB=2^20B
  3. 1GB=1024MB=2^30B

答案:12.5 * 2^20=12.5 * 1024 * 1024=13107200

在这里插入图片描述
在这里插入图片描述

  • 有向图:边的取值范围i:[0, n(n-1)],有n(n-1)条的有向图称为有向完全图(任意两个顶点之间都存在方向相反的两条弧)
  • 无向图:边的取值范围i:[0, n(n-1)/2],有n(n-1)/2条边时的无向图称为完全图(任意两个顶点之间都存在边)

答案:2019 *(2019-1)=4074342

在这里插入图片描述
还有这个:
在这里插入图片描述

  • 有n个顶点的无向连通图最多有n(n-1)/2条边,最少有n-1条边。

答案:2018

在这里插入图片描述
注意!这里有相同的字符‘A’,所以答案不是 7!

static HashSet<String> set = new HashSet<>();

	public static void main(String[] args) {
		char[] cs = "LANQIAO".toCharArray();
		dfs(cs, 0);
		System.out.println(set.size());// 因为存在相同的字符
	}

	// 字母排列
	static public void dfs(char[] cs, int index) {
		if (index == cs.length) {
			set.add(new String(cs));
			return;
		}
		for (int i = index; i < cs.length; i++) {
			swap(cs, index, i);
			dfs(cs, index + 1);
			swap(cs, index, i);
		}
	}

	public static void swap(char[] cs, int i, int j) {
		char temp = cs[i];
		cs[i] = cs[j];
		cs[j] = temp;
	}

答案:2520

在这里插入图片描述
方法一:暴力
先求出全排列,然后判断是否合法

public class 合法括号的个数 {
	static HashSet<String> set = new HashSet<>();

	public static void main(String[] args) {
		String string = "()()()()";
		char[] cs = string.toCharArray();
		dfs(cs, 0);
		List<String> list = new ArrayList<>();
		list.addAll(set);
		System.out.println(set.size());// 因为存在相同的字符
		System.out.println(list);
	}

	static public void dfs(char[] cs, int index) {
		if (index == cs.length) {
			if (vaild(cs))
				set.add(new String(cs));
			return;
		}
		for (int i = index; i < cs.length; i++) {
			swap(cs, index, i);
	//当前位置的index和后续所有的数字都进行交换,交换过后,就是下一个位置和后续所有位置进行交换
			dfs(cs, index + 1);
			swap(cs, index, i);
		}
	}

	public static void swap(char[] cs, int i, int j) {
		char temp = cs[i];
		cs[i] = cs[j];
		cs[j] = temp;
	}

	// 验证是否合法
	static public boolean vaild(char[] cs) {
		Stack<Character> stack = new Stack<>();
		for (int i = 0; i < cs.length; i++) {
			if (stack.isEmpty() || cs[i] == '(') {
				stack.add(cs[i]);
			} else if (stack.peek() == '(' && cs[i] == ')') {
				stack.pop();
			}
		}
		return stack.isEmpty();
	}
}

方法二:根据特性来求解
因为括号是成对的,输入的n=4,那么说明左括号为4个,右括号为4个

  1. 如果合法:左括号数=右括号数
  2. 否则:
    (1)左括号数<n,则应该加入左括号。
    (2)左括号数>右括号数,则应该加入右括号。
public class 括号 {
	public static void main(String[] args) {
		括号 test = new 括号();
		test.generateParenthesis(4);
	}

	List<String> reStrings = new ArrayList<>();

	public List<String> generateParenthesis(int n) {
		dfs(0, 0, n, new StringBuilder());
		System.out.println(reStrings.size());
		return reStrings;
	}

	public void dfs(int cntL, int cntR, int n, StringBuilder builder) {
		if (cntL == cntR && cntL == n) {
			reStrings.add(builder.toString());
			return;
		}
		if (cntL < n) {
			builder.append("(");
			dfs(cntL + 1, cntR, n, builder);
			builder.deleteCharAt(builder.length() - 1);
		}
		if (cntL > cntR) {
			builder.append(")");
			dfs(cntL, cntR + 1, n, builder);
			builder.deleteCharAt(builder.length() - 1);
		}
	}
}

答案:14

在这里插入图片描述

public class 反倍数 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int a = sc.nextInt();
		int b = sc.nextInt();
		int c = sc.nextInt();
		//sc.close();
		int count = 0;
		for (int i = 1; i <= n; i++) {
			if (i % a != 0 && i % b != 0 && i % c != 0) {
				count++;
			}
		}
		System.out.println(count);

	}
}

在这里插入图片描述

import java.util.Scanner;

public class 凯撒密码 {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		String string = scanner.nextLine();
		char[] cs = string.toCharArray();
		for (int i = 0; i < cs.length; i++) {
			if (cs[i] < 'x') {
				cs[i] = (char) (cs[i] + 3);
			} else {
				switch (cs[i]) {
				case 'x':
					cs[i] = 'a';
					break;
				case 'y':
					cs[i] = 'b';
					break;
				case 'z':
					cs[i] = 'c';
					break;
				}
			}
		}
		System.out.println(new String(cs));
	}
}

或者

public class lanqiao5th {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		String str = in.next();
		char[] chs = str.toCharArray();
		for (int i = 0; i < chs.length; i++) {
			if (chs[i] == 'x') {
				chs[i] = 'a';
			} else if (chs[i] == 'y') {
				chs[i] = 'b';
			} else if (chs[i] == 'z') {
				chs[i] = 'c';
			} else {
				chs[i] = (char) (chs[i] + 3);
			}
		}
		System.out.println(new String(chs));
	}

}

在这里插入图片描述

1 2 3 4 5
14 15 16 17 6
13 20 19 18 7
12 11 10 9 8

样例输出:15

public class 螺旋矩阵 {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();// 行数
		int m = scanner.nextInt();// 列数
		int r = scanner.nextInt();// 第r行,注意下标
		int c = scanner.nextInt();// 第c行
		int[][] arr = new int[n][m];
		fullArr(arr);
		for (int[] a : arr) {
			System.out.println(Arrays.toString(a));
		}
		System.out.println(arr[r - 1][c - 1]);
	}

	public static void fullArr(int[][] matrix) {
		int n = matrix.length;
		int m = matrix[0].length;
		int left = 0, right = m - 1;
		int top = 0, bottom = n - 1;
		int num = 1;
		while (num <= n * m) {
			// 向右
			for (int i = left; i <= right; i++) {
				matrix[top][i] = num++;
			}
			// 向下
			top++;
			for (int i = top; i <= bottom; i++) {
				matrix[i][right] = num++;
			}
			// 向左
			right--;
			for (int i = right; i >= left; i--) {
				matrix[bottom][i] = num++;
			}
			// 向上
			bottom--;
			for (int i = bottom; i >= top; i--) {
				matrix[i][left] = num++;
			}
			// 向右
			left++;
		}
	}
}

摆动序列

问题描述
  如果一个序列的奇数项都比前一项大,偶数项都比前一项小,则称为一个摆动序列。即 a[2i]<a[2i-1], a[2i+1]>a[2i]。
  小明想知道,长度为 m,每个数都是 1 到 n 之间的正整数的摆动序列一共有多少个。

输入格式
  输入一行包含两个整数 m,n。

输出格式
  输出一个整数,表示答案。答案可能很大,请输出答案除以10000的余数。

样例输入
3 4
样例输出
14

样例说明
  以下是符合要求的摆动序列:
  2 1 2
  2 1 3
  2 1 4
  3 1 2
  3 1 3
  3 1 4
  3 2 3
  3 2 4
  4 1 2
  4 1 3
  4 1 4
  4 2 3
  4 2 4
  4 3 4

评测用例规模与约定
  对于 20% 的评测用例,1 <= n, m <= 5;
  对于 50% 的评测用例,1 <= n, m <= 10;
  对于 80% 的评测用例,1 <= n, m <= 100;
  对于所有评测用例,1 <= n, m <= 1000。

只能过一部分:

public class 摆动序列 {
	static HashSet<List<Integer>> set = new HashSet<>();

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int m = scanner.nextInt();// 多长
		int n = scanner.nextInt();// 1~n
		int[] arr = new int[n];
		for (int i = 0; i < n; i++) {
			arr[i] = i + 1;
		}
		List<Integer> list = new ArrayList<Integer>();
		for (int i = 0; i < n; i++) {
			list.add(i + 1);
			dfs(arr, list, 0, m);
			list.remove(list.size() - 1);
		}

		System.out.println(set.size() % 10000);
	}

	// 奇数项比前一项大
	// 偶数项比前一项小
	public static void dfs(int[] arr, List<Integer> list, int index, int m) {
		if (index == m - 1) {
			set.add(new ArrayList<>(list));
			return;
		}
		if (index % 2 != 0) {// 数组下标从0开始,而序列以1开始
			for (int i = 0; i < arr.length; i++) {// 奇数项
				if (arr[i] > list.get(index)) {
					list.add(arr[i]);
					dfs(arr, list, index + 1, m);
					list.remove(list.size() - 1);
				}
			}
		} else {
			for (int i = 0; i < arr.length; i++) {// 偶数项
				if (arr[i] < list.get(index)) {
					list.add(arr[i]);
					dfs(arr, list, index + 1, m);
					list.remove(list.size() - 1);
				}
			}
		}

	}
}

改进:我很努力去看了,但是还是看不懂,水平没有到,水平到了自然看得懂
别人的代码:很强!

public class 摆动序列2 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int m = sc.nextInt();
		int n = sc.nextInt();
		sc.close();
		// dp[i][j] i表示第多少位,j表示一个分界线
		// 奇数行就是大于j的方案数,偶数行就是小于j的方案数
		// 奇数要比前面的大,所以要大于的,偶数要比前面的小,所以要小于的

		int[][] dp = new int[m + 2][n + 2];
		// 初始化边界
		for (int i = 1; i <= n; i++) {
			dp[1][i] = n - i + 1;
		}

		for (int i = 2; i <= m; i++)
			if ((i & 1) == 1) {
				// 奇数的话是要比前面大的,所以用倒序
				for (int j = n; j >= 1; j--) {
					dp[i][j] = (dp[i - 1][j - 1] + dp[i][j + 1]) % 10000;
				}
			} else {
				for (int j = 1; j <= n; j++) {
					dp[i][j] = (dp[i - 1][j + 1] + dp[i][j - 1]) % 10000;
				}
			}
		// 判断奇偶从此我要改成这个了,一位位运算确实快
		// m&1,就是把m换成二进制看看最后一位是不是1,如果是1证明就是奇数,如果是0证明是偶数
		int result = (m & 1) == 1 ? dp[m][1] : dp[m][n];
		System.out.println(result);

	}
}

小明植树

问题描述
  小明和朋友们一起去郊外植树,他们带了一些在自己实验室精心研究出的小树苗。
  小明和朋友们一共有 n 个人,他们经过精心挑选,在一块空地上每个人挑选了一个适合植树的位置,总共 n 个。他们准备把自己带的树苗都植下去。
  然而,他们遇到了一个困难:有的树苗比较大,而有的位置挨太近,导致两棵树植下去后会撞在一起。
  他们将树看成一个圆,圆心在他们找的位置上。如果两棵树对应的圆相交,这两棵树就不适合同时植下(相切不受影响),称为两棵树冲突。
  小明和朋友们决定先合计合计,只将其中的一部分树植下去,保证没有互相冲突的树。他们同时希望这些树所能覆盖的面积和(圆面积和)最大。
输入格式
  输入的第一行包含一个整数 n ,表示人数,即准备植树的位置数。
  接下来 n 行,每行三个整数 x, y, r,表示一棵树在空地上的横、纵坐标和半径。
输出格式
  输出一行包含一个整数,表示在不冲突下可以植树的面积和。由于每棵树的面积都是圆周率的整数倍,请输出答案除以圆周率后的值(应当是一个整数)。
样例输入
6
1 1 2
1 4 2
1 7 2
4 1 2
4 4 2
4 7 2
样例输出
12
评测用例规模与约定
  对于 30% 的评测用例,1 <= n <= 10;
  对于 60% 的评测用例,1 <= n <= 20;
  对于所有评测用例,1 <= n <= 30,0 <= x, y <= 1000,1 <= r <= 1000。

自己写的代码

public class 小明植树 {
	static int[] x = new int[30];
	static int[] y = new int[30];
	static int[] r = new int[30];
	static int max = -1;
	static boolean[] visited = new boolean[30];

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();
		for (int i = 0; i < n; i++) {
			x[i] = scanner.nextInt();
			y[i] = scanner.nextInt();
			r[i] = scanner.nextInt();
		}
		scanner.close();
		dfs(new ArrayList<>(), 0, n, 0);
		System.out.println(max);
	}

	public static void dfs(List<int[]> list, int index, int n, int sum) {
		max = Math.max(max, sum);
		if (index >= n - 1) {// 有可能全部都冲突,那么最多种一棵树
			return;
		}
		for (int i = index; i < n; i++) {
			int[] a = { x[i], y[i], r[i] };
			if (!visited[i]) {// 未访问过
				boolean isconflict = false;
				for (int j = 0; j < list.size(); j++) {
					if (!notConflict(list.get(j), a)) {// 两两比较
						isconflict = true;
						break;
					}
				}
				if (!isconflict) {// 不冲突
					visited[i] = true;
					list.add(a);
					dfs(list, i + 1, n, sum + a[2] * a[2]);
					list.remove(list.size() - 1);
					visited[i] = false;
				}
			}
		}
	}

	public static boolean notConflict(int[] a, int[] b) {
		return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) >= (a[2] + b[2]) * (a[2] + b[2]);
	}
}

借鉴别人写的:
别人可能采用的是邻接矩阵的思想

public class 小明植树2 {
	public static boolean[][] flag = new boolean[31][31];; // 判断树i和树j能否一起种植,False为不能一起种植,True为可以一起种植
	static boolean[] vis = new boolean[31]; // 标志当前树是否被种植
	public static int[] x = new int[31];
	public static int[] y = new int[31];
	public static int[] r = new int[31];
	public static int n = 0, max = -1;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		for (int i = 1; i <= n; i++) {
			x[i] = sc.nextInt();
			y[i] = sc.nextInt();
			r[i] = sc.nextInt();
		}
		for (int i = 1; i <= n; i++) {
			for (int j = i + 1; j <= n; j++) {// 判断i和j能不能共存
				boolean bo = ((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]) > (r[i] + r[j])
						* (r[i] + r[j]));
				flag[i][j] = bo;
				flag[j][i] = bo;
			}
		}
		dfs(new ArrayList<>(), 0);
		System.out.println(max);
	}

	public static void dfs(ArrayList<Integer> trees, int sum) {
		max = Math.max(max, sum);
		Label: for (int i = 1; i <= n; i++) {
			if (vis[i])// vis:树i已经在列表中
				continue;
			for (int j = 0; j < trees.size(); j++) {
				int t = trees.get(j);
				if (!flag[i][t]) { // flag:i和t能否一起种植
					// 如果i不在列表,且i和列表中的树起冲突,i可以跳过
					continue Label;
				}
			}
			trees.add(i);
			vis[i] = true;
			dfs(trees, sum + r[i] * r[i]);
			vis[i] = false;
			trees.remove(trees.size() - 1);
		}
	}

}

补充:
在这里插入图片描述
特点:
1.无向图的邻接矩阵是对称的,且主对角线元素全为0(因为自己到自己没有边)。
2.顶点i的度=第i行(列)中1的个数。
3.完全图的邻接矩阵中,主对角元素为0,其余全为1。

通过这道题,我学到了:

  1. static boolean[] vis = new boolean[31]; 根据数据范围,设置一个满足所有条件的数组
  2. max = Math.max(max, sum);放在dfs开头,避免因 不能执行if(index==n-1){ max=Math.max(max,sum)}语句而出错(因为有可能所有的树都冲突,就不会dfs到n-1,可以在for循环里面就执行完了
  3. dfs(list, i + 1, n, sum + a[2] * a[2]); dfs的时候将sum传下去,可以更新max的值,也不用额外写代码求种植的面积。
  4. 邻接矩阵的表示。

收获良多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值