链接:https://pan.baidu.com/s/1DuQ3CSGrkEIS7HtnW4_uHA
提取码:wog6
A组题解:https://blog.csdn.net/qq_44467578/article/details/104521746
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//文件读入部分
String pathname="D:\\java\\team.txt";
int[][] team=new int[20][6];
try {
FileReader reader = new FileReader(pathname);
BufferedReader br = new BufferedReader(reader);
Scanner sc=new Scanner(br);
for(int i=0;i<20;i++) {
for(int j=0;j<6;j++) {
team[i][j]=sc.nextInt();
}
}
} catch (IOException e) {
e.printStackTrace();
}
//暴力循环所有情况,其实手算就行=-= 结果490
int maxSum=0;
int sum=0;
for (int i = 0; i < 20; i++)
for (int j = 0; j < 20; j++)
for (int k = 0; k < 20; k++)
for (int h = 0; h < 20; h++)
for (int g = 0; g < 20; g++)
if ((i != j && i != k && i != h && i != g) && (j != k && j != h && j != g)
&& (k != h && k != g) && h != g) {
sum = team[i][1] + team[j][2] + team[k][3] + team[h][4] + team[g][5];//[i][0]是序号
if (sum > maxSum)
maxSum =sum;
}
System.out.println(maxSum);
sc.close();
}
}
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
String s="0100110001010001";
//统计非空不重合的总数,很容易想到利用集合去重
Set<String> set=new HashSet<String>();
for(int i=0;i<s.length();i++) {//起点从0到末尾
for(int j=i+1;j<s.length()+1;j++) {//终点从1到末尾+1
set.add(s.substring(i, j));//因为substring左闭右开
}
}
//结果为100
System.out.println(set.size());
}
}
public class Main {
public static void main(String[] args) {
//类似斐波那契数列?算下去的话int long 甚至大数类估计都存不下
//题目要求20190324项的最后四位数字,也就是变相的告诉我们运算过程只和每个数的后四位有关系
//结果4659
int a = 1, b = 1, c = 1;
// 要是求第四项,则i < 4, 同理推得求20190324,则i < 20190324。
for (int i = 3; i < 20190324; i++) {
int temp = (a + b + c) % 10000;
a = b;
b = c;
c = temp;
}
System.out.println(c);
}
}
public class Main {
public static void main(String[] args) {
//组成2019的三个数有哪几类?
//1.ABC类排列方式为六种(ABC,ACB,BAC,BCA,CAB,CBA)
//2.AAB类排列方式有三种(AAB,ABA,BAA)1009 1009 1
//3.AAA类排列方式一种。673 673 673
//而题目要求把2019分解成3个各不相同的正整数之和也就是说只保留ABC类的组合方式
//分解问题,先取一个任取一个i,则问题转化为2019-i有多少两个数组成的方法
//将这个数分成两半,j从i+1到中间值取值,则k必然是中间值到末尾取值,确保了i,j,k不同
int n = 2019;
int sum = 0;
String s;
for (int i = 1; i < n; i++) {
s = String.valueOf(i);
if (s.contains("2") || s.contains("4"))
continue;
for (int j = i + 1; j < (n - i + 1) / 2; j++) {
s = String.valueOf(j);
if (s.contains("2") || s.contains("4"))
continue;
int k = n - i - j;
s = String.valueOf(k);
if (s.contains("2") || s.contains("4"))
continue;
sum++;
}
}
System.out.println(sum);
}
}
【问题描述】 下图给出了一个迷宫的平面图,其中标记为 1 的为障碍,标记为 0 的为可 以通行的地方。
010000
000100
001001
110000
迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这 个它的上、下、左、右四个方向之一。 对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫, 一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。 对于下面这个更复杂的迷宫(30 行 50 列),请找出一种通过迷宫的方式, 其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。 请注意在字典序中D
10100000101000100110101010111110011000010000111010 00111000001010100001100010000001000101001100001001 11000110100001110010001001010101010101010001101000 00010000100100000101001010101110100010101010000101 11100100101001001000010000010101010100100100010100 00000010000000101011001111010001100000101010100011 10101010011100001000011000010110011110110100001000 10101010100001101010100101000010100000111011101001 10000000101100010000101100101101001011100000000100 10101001000000010100100001000100000100011110101001 00101001010101101001010100011010101101110000110101 11001010000100001100000010100101000001000111000010 00001000110000110101101000000100101001001000011101 10100101000101000000001110110010110101101010100001 00101000010000110101010000100010001001000100010101 10100001000110010001000010101001010101011111010010 00000100101000000110010100101001000001000000000010 11010000001001110111001001000011101001011011101000 00000110100010001000100000001000011101000000110011 10101000101000100010001111100010101001010000001000 10000010100101001010110000000100101010001011101000 00111100001000010000000110111000000001000000001011 10000001100111010111010001000110111010101101111000
Excel大法
BFS
import java.util.ArrayDeque;
import java.util.Scanner;
class Main {
static int[][] map = new int[30][50];// 迷宫
static int[][] dis = new int[30][50];// 每个位置到终点的最短路径
static int[] dx = { 1, 0, 0, -1 }, dy = { 0, -1, 1, 0 };
static String[] dir = { "D", "L", "R", "U" };//最小字典序
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
for (int i = 0; i < 30; i++) {
String s = sc.nextLine();
for (int j = 0; j < 50; j++) {
map[i][j] = s.charAt(j) - '0';
}
}
int n = 30, m = 50;
bfs(n, m);//求出每个位置到终点的最短距离
StringBuffer bf = new StringBuffer();//用变长字符串存储最终路径
int x = 0, y = 0;
while (x != n-1 || y != m-1 ) {//dfs
for (int i = 0; i < 4; i++) {//以最小字典序探索四个方向
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && map[nx][ny] == 0) {
if (dis[x][y] == 1 + dis[nx][ny]) {//如果走的是最短路径
x = nx;
y = ny;
bf.append(dir[i]);//把走的方向存储
break;//跳出for循环,即走了当前方向就不走其他方向了
}
}
}
}
System.out.println(bf);
}
static void bfs(int n, int m) {
ArrayDeque<Node> q = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
dis[i][j] = -1;
}
}
dis[n - 1][m - 1] = 0;
q.offer(new Node(n - 1, m - 1));
while (!q.isEmpty()) {
Node node = q.peek();
q.pop();
for (int i = 0; i < 4; i++) {
int x = node.x + dx[i];
int y = node.y + dy[i];
if (x >= 0 && x < n && y >= 0 && y < m && dis[x][y] == -1 && map[x][y] == 0) {
dis[x][y] = dis[node.x][node.y] + 1;
q.offer(new Node(x, y));
}
}
}
}
static class Node {
int x;
int y;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
}
}
package 蓝桥;
import java.util.Scanner;
//直接循环遍历,用indexof或者contains判断即可
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int sum = 0;
for (int i = 1; i <= n; i++) {
String s = Integer.toString(i);
if (s.indexOf("2") != -1 || s.indexOf("0") != -1 || s.indexOf("1") != -1
|| s.indexOf("9") != -1) {
sum += i;
}
}
System.out.println(sum);
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
static class Order implements Comparable<Order> {
int ts;
int id;
public Order(int ts, int id) {//订单结构体
this.ts = ts;
this.id = id;
}
@Override
public int compareTo(Order other) {//重写比较方法,用于排序时内部调用
if (ts == other.ts) {
if (id > other.id) {
return 1;
} else if (id < other.id) {
return -1;
}
return 0;
}
return ts > other.ts ? 1 : -1;
}
@Override
public boolean equals(Object obj) {//重写比较方法,用于两个订单比较
Order other = (Order) obj;
return ts == other.ts && id == other.id;
}
}
static Order[] orders;// 订单组
static boolean[] priority;// 优先队列
static int[] rank;// 每个店优先级
static int[] last;// 每个店上次有订单的时间
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] date = br.readLine().split("\\s+");
int N = Integer.parseInt(date[0]) + 1;// 店数,因为编号是1~N
int M = Integer.parseInt(date[1]);// 订单数
int T = Integer.parseInt(date[2]);// 时长
orders = new Order[M];
priority = new boolean[N];
rank = new int[N];
last = new int[N];
for (int i = 0; i < M; i++) {
date = br.readLine().split("\\s+");
int ts = Integer.parseInt(date[0]);
int id = Integer.parseInt(date[1]);
orders[i] = new Order(ts, id);
}
Arrays.sort(orders);//将订单按时间排序,时间相同则编号小的在前
for (int i = 0; i < M;) {//遍历订单
int j = i;
while (j < M && orders[i].equals(orders[j])) {
//查询每个编号在当前时间内的订单总数
j++;
}
//当前计数的店的编号,时间,订单数
int id = orders[i].id, ts = orders[i].ts, ans = j - i;
i = j;
//该时刻前减少的优先级
rank[id] -= ts - last[id] - 1;
if (rank[id] < 0)
rank[id] = 0;
if (rank[id] <= 3)
priority[id] = false;
//该时刻增加的优先级
rank[id] += ans * 2;
if (rank[id] > 5)
priority[id] = true;
//记录该店最后有订单的时间
last[id] = ts;
}
//搜寻完订单后要再更新一次
for (int i = 1; i < N; i++) {
if (last[i] < T) {
rank[i] -= T - last[i];
if (rank[i] <= 3)
priority[i] = false;
}
}
//输出答案
int res = 0;
for (int i = 0; i < N; i++) {
if (priority[i]) {
res++;
}
}
System.out.println(res);
br.close();
}
}
package 蓝桥;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int K = sc.nextInt();
sc.nextLine();
String text = sc.nextLine();
// 分割字符串,按照空格和.分割字符,若是(.空格)分割后为空字符串。
String[] words = text.split("\\s+|\\.");// \s:空字符 +:多次出现 |:选择 \.:.
int[] wordsLength = new int[words.length];
// 将分割的字符串的长度值存储,避免三重循环中调用String.length();
for (int i = 0; i < words.length; i++) {
wordsLength[i] = words[i].length();
}
int num = 0;
// Alice ——> Bob的距离
for (int i = 0; i < words.length; i++) {
if (words[i].equals("Alice")) {
for (int j = i + 1; j < words.length; j++) {
int sum = 1;
if (words[j].equals("Bob")) {
for (int k = i + 1; k < j; k++) {
// 每个单词的长度加空格占据的长度
sum += wordsLength[k] + 1;
}
if (sum <= K) {
num++;
}
}
}
}
}
// Bob ——> Alice的距离
for (int i = 0; i < words.length; i++) {
if (words[i].equals("Bob")) {
for (int j = i + 1; j < words.length; j++) {
int sum = 1;
if (words[j].equals("Alice")) {
for (int k = i + 1; k < j; k++) {
sum += wordsLength[k] + 1;
}
if (sum <= K) {
num++;
}
}
}
}
}
System.out.println(num);
sc.close();
}
}
package 蓝桥;
import java.util.Arrays;
import java.util.Scanner;
/**
* 后缀表达式就是吓唬人的,平常所用的是中缀表达式,变形就是后缀,后缀只是方便机器运算省略括号而已,这道题按中缀做就好,又不要求输出表达式
* 1.如果只有+,则遍历数组累加即可;
* 2.如果只有-,首先从小到大排序,然后分两种情况考虑:
* (1)含有负数,例如 [-2, -1, 1, 2, 3],四个减号
* 运算过程为 3- (-1) - (-2 - 1 - 2) = 3 + 1 + 2 + 1 +2
* 即只要含有负数,负数转正数,全部相加即可
* (2)全部是正数,例如 [1, 2, 3],两个减号
* 运算过程为 3 - (1 - 2) = 3 + 2 - 1,
* 即除了最小值以外的正数相加减去最小值
* 3.如果有+号,有-号,则讨论减号的个数与负数的个数,分两种情况讨论:
* ( 1)减>=负:例如 [-2, -1, 1, 2, 3],两个减号两个加号
* 运算过程为 3 - (-1) - (-2) + 1 + 2
* 即每个减号匹配一个负数将其变正,然后从大到小累加这些数,再减去和剩下的减号数量相等的数
* (2)减<负:例如 [-2,-1,1],一个加号一个减号,运算过程为 1 - (-2 + -3)
* 即把负数相加来消除负数,这时候有两种情况
* (2.1)全是负数,如 [-1, -2, -3, -4, -5],一个加号三个减号
* 运算过程为 -1 - ( -4 + -5 ) - (-3) - (-2)
* 即首先排序选择其中的最大值,加上其他数字的绝对值就行。
* (2.2)有正数,有负数,如 [-4,-3,-2,-1,1],两个加号两个减号
* 运算过程为 1 - ( -4 + -3 + -2 + -1 ) - -1
* 即首先排序选择其中的最大值,加上其他数字的绝对值就行。
* 显然,两种情况的处理方式是一样的
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int add = sc.nextInt();//+
int reduce = sc.nextInt();//-
int num = add + reduce + 1;//数
int[] number = new int[num];
for (int i = 0; i < num; i++) {
number[i] = sc.nextInt();
}
int sum = 0;
if (reduce == 0) {//1
for (int i = 0; i < num; i++) {
sum += number[i];
}
}
if (add == 0) {//2
Arrays.sort(number);
if (number[0] < 0) {//2.1
for (int i = 0; i <= reduce; i++) {
if (number[i] > 0)
sum += number[i];
else
sum -= number[i];
}
} else {//2.2
for (int i = 1; i <= reduce; i++) {
sum += number[i];
}
sum -= number[0];
}
}
if (add != 0 && reduce != 0) {//3
int negativeNumber = 0;//负数
for (int i = 0; i < num; i++) {
if (number[i] < 0) {
negativeNumber++;
}
}
Arrays.sort(number);
if (reduce >= negativeNumber) {//3.1
int temp = reduce;
for (int i = 0; i < negativeNumber; i++) {
number[i] = -number[i];
temp--;
}
Arrays.sort(number);
for (int i = num - 1; i >= temp; i--) {
sum += number[i];
}
for (int i = temp - 1; i >= 0; i--) {
sum -= number[i];
}
} else {//3.2
sum += number[num - 1];
for (int i = 0; i < num - 1; i++) {
if (number[i] > 0)
sum += number[i];
else
sum -= number[i];
}
}
}
System.out.println(sum);
sc.close();
}
}
对于这个前缀和序列,S[0]和S[n]是不能动的,那么
(1)S[0]最小,S[n]最大时
这种情况下,只要将Sn升序排列,相邻两项之间的差必然是最小的,只要求出其中的最大值即可
但是由于a[i]有负值,所以这种情况是不太可能的,所以重点讨论第二种情况
(2)S[0],S[n]都不是最值时
我们已经知道了如果Sn是有序序列,那么目标值只要遍历一遍就能求出,所以这种情况下我们仍旧要对Sn排序,但不是直接排序,而是像图中的这种思路
即设min{ s[ 0 ],s[ n ] } 做起点,max{ s[ 0 ],s[ n ] }做终点;还需要注意的是特殊情况,即 s[ 0 ] == s[ n ] 时,我们须确保起点的下标要小于终点的下标,不然会发生取数产生重叠区。
先将Sn排序,然后以S0,Sn为界取数
如何取数呢?隔一个数取一个数显然是最好的解决办法了,向左取数时候就留下了间隔一个数的一组数,留下之后反方向向右取的数。
取数完成后遍历一遍找到差绝对值的最大值,输出。
package 蓝桥;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws NumberFormatException, IOException {
// 可能会遇到大数量的数字 使用流读取数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine().trim());// 数据组数
int n;// 每组数据数字个数
String[] a;// 按空格分割字符串,每个字符串对应下标+1处的灵能
int[] s;// 存储灵能
int[] st;// 记录排序后的s
boolean[] visit;//记录s中的值是否已经参与排序
while (N-- >= 0) {
n = Integer.parseInt(br.readLine().trim());
a = br.readLine().split("\\s+");
s = new int[a.length + 1];
st = new int[a.length + 1];
visit=new boolean[a.length + 1];
for (int i = 1; i <= n; i++) {
// 对每组数据进行前缀和的计算
s[i] = s[i - 1] + Integer.parseInt(a[i - 1]);
}
int s0 = s[0];
int sn = s[n];
if (s[0] > s[n]) {
int temp = s[0];
s[0] = s[n];
s[n] = temp;
}
Arrays.sort(s);
for (int i = 0; i <= n; i++)
if (s0 == s[i]) {
s0 = i;
break;
}
for (int i = n; i >= 0; i--)
if (sn == s[i]) {
sn = i;
break;
}
int l = 0, r = n;
for (int i = s0; i >= 0; i-=2) {
st[l++] = s[i];
visit[i]=true;
}
for(int i=sn;i<=n;i+=2) {
st[r--]=s[i];
visit[i]=true;
}
for(int i=0;i<=n;i++) {
if(!visit[i]) {
st[l++]=s[i];
}
}
int max=0;
for(int i=1;i<=n;i++) {
max=Math.max(max, Math.abs(st[i]-st[i-1]));
}
System.out.println(max);
}
}
}
如果觉得上一种解法难以理解,可以换一个思路简单实现较为复杂的解法。
在题目转换之后的基础上,确定S[0],S[n]是顶点,可以将S[1]~S[n-1]全排列,即枚举所有可能的转换情况,然后取得目标值。这种方法在数据量大的情况下很可能超时。
package 蓝桥;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
// 存储结果
static int min = Integer.MAX_VALUE;
public static void main(String[] args) throws NumberFormatException, IOException {
// 可能会遇到大数量的数字 使用流读取数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine().trim());// 数据组数
int result = 0;// 保存最终结果
while (N-- >= 0) {
int n = Integer.parseInt(br.readLine().trim());// 每组数据数字个数
String[] a = br.readLine().split(" +");// 按空格分割字符串,每个字符串对应下标+1处的灵能
int[] s = new int[a.length + 1];
for (int i = 1; i <= n; i++) { // 对每组数据进行前缀和的计算
s[i] = s[i - 1] + Integer.parseInt(a[i - 1]);
}
// dfs的时候存储中间前缀和,S0,Sn不参与排列
int[] temp = new int[s.length];
boolean[] visit = new boolean[s.length];// 递归的时候记录前缀和数组里面的哪些数已经被用过
// dfs
dfs(temp, s, visit, 1);
result = min;
System.out.println(result);
min = Integer.MAX_VALUE;
}
}
private static void dfs(int[] temp, int[] s, boolean[] visit, int n) {
// 当我们n等于这个的时候 说明我们已经找到一种情况了 这个时候判断这个数是否比min小
if (n == s.length - 1) {
int res = fun_res(temp, n);
// 如果小,那么进行替换
if (res < min) {
min = res;
}
// 一定要记得退出当前栈
return;
}
// 对于temp数组的每一个位置,我们每一种情况都要试试
for (int j = 1; j < s.length - 1; j++) {
// 如果sum数组里面的第j个数我们没有用过
if (!visit[j]) {
// 标记 当前数已经被用过了
visit[j] = true;
temp[n] = s[j]; // 把s数组里面的值赋给temp数组
// 下面是非常重要的剪枝操作 如果没有这个步骤,那么可能会超时
int t = fun_res(temp, n); // 如果temp数组当前的结果值已经比min要大了 ,那么我们就不用进行下面的递归了
if (t > min) {
visit[j] = false; // 表示我们没有用 sum[j]当前的值
continue; // 结束本层循环
}
// dfs深搜
dfs(temp, s, visit, n + 1);
// 深搜结束后,我们把当前的值设置为没用过,以备后来用
visit[j] = false;
}
}
}
// 此函数是找出 一个前缀和数组中 相邻两元素差的绝对值的最大值
public static int fun_res(int[] sum, int n) {
int max = Integer.MIN_VALUE;
for (int i = 1; i <= n; i++) {
if (Math.abs(sum[i] - sum[i - 1]) > max) {
max = Math.abs(sum[i] - sum[i - 1]);
}
}
return max;
}
}