敲黑板!!!重点重点!!!学计算机你连这个都记不住,丢你男朋友的脸(没有男朋友的当我没有说)
- 1KB=1024B=2^10B
- 1MB=1024KB=2^20B
- 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)左括号数<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。
通过这道题,我学到了:
- static boolean[] vis = new boolean[31]; 根据数据范围,设置一个满足所有条件的数组
- max = Math.max(max, sum);放在dfs开头,避免因 不能执行if(index==n-1){ max=Math.max(max,sum)}语句而出错(因为有可能所有的树都冲突,就不会dfs到n-1,可以在for循环里面就执行完了
- dfs(list, i + 1, n, sum + a[2] * a[2]); dfs的时候将sum传下去,可以更新max的值,也不用额外写代码求种植的面积。
- 邻接矩阵的表示。
收获良多。