哈尔滨网站制作工具百度搜索优化
此题单为算法基础精选题单,包含蓝桥杯常考考点以及各种经典算法,可以帮助你打牢基础,查漏补缺。
本题单目标是冲击蓝桥杯省一国一,团体程序天梯赛个人国三、XCPC区域赛铜/银奖
前言
本次题单重点关注模拟类问题,DFS问题,BFS问题
目录
模拟类题型
一、最大子矩阵
二、 世纪末的星期
三、图像相似度
四、操作系统
DFS题型
五 、老子的全排列呢
六、皇后问题
七、 池塘
BFS题型
八、迷宫
九、八数码问题
十、 字符变换
一、最大子矩阵
0最大子矩阵—原题链接
下面是一个 20×20 的矩阵,矩阵中的每个数字是一个 1 到 9 之间的数字,请注意显示时去除了分隔符号。
6985924183938786894117615876963131759284373473483266274834855367125655616786474316121686927432329479135474133499627734472797994592984882468753776983346838791379564934213653657177452192437929387261138293919353216243561277542961447639692577889623397251379473293381443494533129939975611718829888775934996121686889572134852255485345959294726896321249633182425549221359364719193427269656436895944919899246
矩阵中一个子矩阵的值是指子矩阵中所有数值的和。
请问,矩阵中值最大的一个 5×5 的子矩阵的值是多少?
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {// TODO Auto-generated method stubScanner scan = new Scanner(System.in);//在此输入您的代码...
// int arr[][]=new int[20][20];
// String s="6985924183938786894117615876963131759284373473483266274834855367125655616786474316121686927432329479135474133499627734472797994592984882468753776983346838791379564934213653657177452192437929387261138293919353216243561277542961447639692577889623397251379473293381443494533129939975611718829888775934996121686889572134852255485345959294726896321249633182425549221359364719193427269656436895944919899246";
// char c[]=s.toCharArray();
// int g=0,max=0,sum=0;
// for(int i=0;i<20;i++) {
// for(int j=0;j<20;j++) {
// arr[i][j]=c[g++]-'0';
// }
// }
// for(int i=0;i<20-4;i++) {
// for(int j=0;j<20-4;j++) {
// sum=arr[i][j]+arr[i][j+1]+arr[i][j+2]+arr[i][j+3]+arr[i][j+4]
// +arr[i+1][j]+arr[i+1][j+1]+arr[i+1][j+2]+arr[i+1][j+3]+arr[i+1][j+4]
// +arr[i+2][j]+arr[i+2][j+1]+arr[i+2][j+2]+arr[i+2][j+3]+arr[i+2][j+4]
// +arr[i+3][j]+arr[i+3][j+1]+arr[i+3][j+2]+arr[i+3][j+3]+arr[i+3][j+4]
// +arr[i+4][j]+arr[i+4][j+1]+arr[i+4][j+2]+arr[i+4][j+3]+arr[i+4][j+4];
// max=sum>max?sum:max;
// }
// }
// System.out.print(max);System.out.print(154);scan.close();}
}
二、 世纪末的星期
世纪末的星期 - 蓝桥云课
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
曾有邪教称 1999 年 12月 31 日是世界末日。当然该谣言已经不攻自破。
还有人称今后的某个世纪末的 12月 31 日,如果是星期一则会....
有趣的是,任何一个世纪末的年份的 12月 31 日都不可能是星期一!!
于是,“谣言制造商”又修改为星期日......
1999年的 12 月 31 日是星期五,请问:未来哪一个离我们最近的一个世纪末年(即 xx99年)的 12 月 31 日正好是星期天(即星期日)?
请回答该年份(只写这个 4 位整数,不要写 12 月 31 等多余信息)
import java.util.Scanner;
import java.time.*;
// 1:无需package
// 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {LocalDate start = LocalDate.of(1999, 12, 31);while(true) {if(start.getDayOfWeek().getValue()==7) {System.out.print(start.getYear());return;}start = start.plusYears(100);}}
}
三、图像相似度
图像相似度
给出两幅相同大小的黑白图像(用0-1矩阵)表示,求它们的相似度。若两幅图像在相同位置上的像素点颜色相同,则称它们在该位置具有相同的像素点。两幅图像的相似度定义为相同像素点数占总像素点数的百分比。
输入描述:
第一行包含两个整数m和n,表示图像的行数和列数,用单个空格隔开。1≤m≤100, 1≤n≤100。之后m行,每行n个整数0或1,表示第一幅黑白图像上各像素点的颜色,相邻两个数用单个空格隔开。之后m行,每行n个整数0或1,表示第二幅黑白图像上各像素点的颜色,相邻两个数用单个空格隔开。
输出描述:
一个实数,表示相似度(以百分比的形式给出),精确到小数点后两位。
示例1
输入
3 3 1 0 1 0 0 1 1 1 0 1 1 0 0 0 1 0 0 1
输出
44.44
import java.awt.datatransfer.SystemFlavorMap;
import java.math.BigInteger;
import java.util.Scanner;import org.omg.PortableInterceptor.IORInterceptor;
import java.sql.*;
public class Main {public static void main(String[] args) {Scanner cin = new Scanner(System.in);int n,m,num=0;int[][] a = new int[105][105];int[][] b = new int[105][105];n=cin.nextInt();m=cin.nextInt();for(int i = 0; i < n; i ++){for(int j = 0; j < m; j ++){a[i][j]=cin.nextInt();}}for(int i = 0; i < n; i ++){for(int j = 0; j < m; j ++){b[i][j]=cin.nextInt();}}for(int i = 0; i < n; i ++){for(int j = 0; j < m; j ++){if(a[i][j] == b[i][j]){num++;}}}System.out.println(String.format("%.2f",num*100.0/(n*m)));}
}
四、操作系统
[HNOI2003]操作系统
写一个程序来模拟操作系统的进程调度。假设该系统只有一个CPU,每一个进程的到达时间,执行时间和运行优先级都是已知的。其中运行优先级用自然数表示,数字越大,则优先级越高。
如果一个进程到达的时候CPU是空闲的,则它会一直占用CPU直到该进程结束。除非在这个过程中,有一个比它优先级高的进程要运行。在这种情况下,这个新的(优先级更高的)进程会占用CPU,而老的只有等待。
如果一个进程到达时,CPU正在处理一个比它优先级高或优先级相同的进程,则这个(新到达的)进程必须等待。一旦CPU空闲,如果此时有进程在等待,则选择优先级最高的先运行。如果有多个优先级最高的进程,则选择到达时间最早的。
输入描述:
输入文件包含若干行,每一行有四个自然数(均不超过108),分别是进程号,到达时间,执行时间和优先级。不同进程有不同的编号,不会有两个相同优先级的进程同时到达。
输入数据已经按到达时间从小到大排序。输入数据保证在任何时候,等待队列中的进程不超过15000个。
输出描述:
按照进程结束的时间输出每个进程的进程号和结束时间
示例1
输入
1 1 5 3 2 10 5 1 3 12 7 2 4 20 2 3 5 21 9 4 6 22 2 4 7 23 5 2 8 24 2 4
输出
1 6 3 19 5 30 6 32 8 34 4 35 7 40 2 42
import java.io.StreamTokenizer;
import java.util.PriorityQueue;
import java.util.Comparator;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Scanner;public class Main {public static void main(String[] args) throws IOException {Scanner in = new Scanner(System.in);PrintWriter out = new PrintWriter(System.out);int ans = 0;int a, b, c, d;Node now, nxt;PriorityQueue<Node> pq = new PriorityQueue<Node>(1, new cmp());while(in.hasNext()) {a = in.nextInt();b = in.nextInt();c = in.nextInt();d = in.nextInt();nxt = new Node(a, b, c, d);while(!pq.isEmpty() && ans + pq.peek().work <= nxt.arr) {now = pq.poll();ans += now.work;out.println(now.num + " " + ans);}if(!pq.isEmpty()) {now = pq.poll();now.work = now.work - nxt.arr + ans;pq.add(now);}pq.add(nxt);ans = nxt.arr;}while(!pq.isEmpty()) {now = pq.poll();ans += now.work;out.println(now.num + " " + ans);}out.close();}static class Node {int num, arr, work, pri;public Node(int num, int arr, int work, int pri) {this.num = num;this.arr = arr;this.work = work;this.pri = pri;}}static class cmp implements Comparator <Node> {public int compare(Node a, Node b) {if(a.pri == b.pri) return a.arr - b.arr;else return b.pri - a.pri;}}}
五 、老子的全排列呢
老子的全排列呢
老李见和尚赢了自己的酒,但是自己还舍不得,所以就耍起了赖皮,对和尚说,光武不行,再来点文的,你给我说出来1-8的全排序,我就让你喝,这次绝不耍你,你能帮帮和尚么?
输入描述:
无
输出描述:
1~8的全排列,按照全排列的顺序输出,每行结尾无空格。
示例1
输入
No_Input
输出
Full arrangement of 1~8
备注:
1~3的全排列 :
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
import java.util.Scanner;public class Main{static int N=100,n;static int []path=new int[N];static boolean flag[]=new boolean[N];public static void main( String[]args ){n=8;dfs(0);}static void dfs(int u){if(u==n){for(int i=0;i<n;i++){System.out.print(path[i]+" ");}System.out.println();return;}for(int i=1;i<=n;i++){if(!flag[i]){flag[i]=true;path[u]=i;dfs(u+1);flag[i]=false;}}}
}
六、皇后问题
皇后问题
给出一个n×n的国际象棋棋盘,你需要在棋盘中摆放n个皇后,使得任意两个皇后之间不能互相攻击。具体来说,不能存在两个皇后位于同一行、同一列,或者同一对角线。请问共有多少种摆放方式满足条件。
输入描述:
一行,一个整数n(1≤n≤12),表示棋盘的大小。
输出描述:
输出一行一个整数,表示总共有多少种摆放皇后的方案,使得它们两两不能互相攻击。
示例1
输入
4
输出
2
import java.util.*;public class Main{static int n,N=10010,ans;static char map[][]=new char[N][N];static boolean[] col=new boolean[N],ug=new boolean[N],udg=new boolean[N];public static void main(String[] args) {Scanner sc=new Scanner(System.in);n=sc.nextInt();for(int i=0;i<n;i++) for(int j=0;j<n;j++)map[i][j]='.';dfs(0);System.out.println(ans);}static void dfs(int x){if(x==n){ans++;for(int i=0;i<n;i++){for(int j=0;j<n;j++){//System.out.print(map[i][j]+" ");}//System.out.println();}//System.out.println();return;}for(int i=0;i<n;i++){if(!col[i]&&!ug[x+i]&&!udg[n-x+i]){map[x][i]='Q';col[i]=ug[x+i]=udg[n-x+i]=true;dfs(x+1);map[x][i]='.';col[i]=ug[x+i]=udg[n-x+i]=false;}}}}
七、 池塘
Lake Counting
由于最近的降雨,Farmer John 的田地里多处积水,用 N x M (1 <= N <= 100;1 <= M <= 100) 的矩形表示。每个方格包含水 ('W') 或旱地 ('.')。农民 John 想弄清楚他的田里有多少个池塘。池塘是一组相连的方块,其中有水,其中一个方块被认为与其所有八个相邻方块相邻。
给定 Farmer John 的田地图,确定他有多少个池塘。
输入描述:
第 1 行:两个以空格分隔的整数:N 和 M * 第 2..N+1 行:每行 M 个字符,表示 Farmer John 字段的一行。每个字符都是 'W' 或 '.'。字符之间没有空格。
输出描述:
第1 行:Farmer John 田地中的池塘数量。
示例1
输入
10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.
输出
3
import java.util.Arrays;
import java.util.Scanner;public class Main{static int N=100,n,m;static char[][] d=new char[N][N];static int dx[]=new int[]{1,0,0,-1,1,-1,1,-1};static int dy[]=new int[]{0,1,-1,0,1,-1,-1,1};static boolean flag[][]=new boolean[N][N];static int ans=0;public static void main( String[]args ){Scanner sc=new Scanner(System.in);n=sc.nextInt();m=sc.nextInt();for(int i=0;i<n;i++) d[i]=sc.next().toCharArray();for(int i=0;i<n;i++){for(int j=0;j<m;j++){if(!flag[i][j]&&d[i][j]=='W'){dfs(i,j);ans++;}}}System.out.println(ans);}static void dfs(int x,int y){if(d[x][y]=='.')return;for(int i=0;i<8;i++){int xx=x+dx[i];int yy=y+dy[i];if(xx>=0&&yy>=0&&xx<n&&yy<m&&d[xx][yy]=='W'&&!flag[xx][yy]){flag[xx][yy]=true;dfs(xx,yy);}}}
}
八、迷宫
迷宫
这是一个关于二维迷宫的题目。我们要从迷宫的起点 'S' 走到终点 'E',每一步我们只能选择上下左右四个方向中的一个前进一格。 'W' 代表墙壁,是不能进入的位置,除了墙壁以外的地方都可以走。迷宫内的 'D' 代表一道上锁的门,只有在持有钥匙的时候才能进入。而 'K' 则代表了钥匙,只要进入这一格,就会自动地拿到钥匙。最后 '.' 则是代表空无一物的地方,欢迎自在的游荡。
本题的迷宫中,起点、终点、门跟钥匙这四个特殊物件,每一个恰好会出现一次。而且,此迷宫的四周 (最上面的一行、最下面的一行、最左边的一列以及最右边的一列) 都会是墙壁。
请问,从起点到终点,最少要走几步呢?
输入描述:
输入的第一行有两个正整数H, W,分别代表迷宫的长跟宽。
接下来的H行代表迷宫,每行有一个长度恰为W的字串,此字串只包含`'S'`, `'E'`, `'W'`, `'D '`, `'K'`, `'.'`这几种字元。
输出描述:
请在一行中输出一个整数代表答案,如果无法从起点走到终点,请输出-1。
示例1
输入
4 12
WWWWWWWWWWWW
WE.W.S..W.KW
W..D..W....W
WWWWWWWWWWWW
输出
20
示例2
输入
6 6
WWWWWW
WEWS.W
W.WK.W
W.WD.W
W.W..W
WWWWWW
输出
-1
备注:
4 ≤ H, W≤ 500
'S', 'E', 'K', 'D'各出现恰好一次
迷宫的四周(最上面的一行、最下面的一行、最左边的一列以及最右边的一列) 都会是 'W'
import java.util.*;
import java.io.*;
class Node {int x, y;int len;boolean hasKey = false;public Node(int x, int y, int len, boolean hasKey) {this.x = x;this.y = y;this.len = len;this.hasKey = hasKey;}
}
public class Main {static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));static final Queue<Node> q = new ArrayDeque<>();static final int[][] dir = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };static int n;static int m;static char[][] mapp;static int bfs() {while (!q.isEmpty()) {Node cur = q.poll();if (mapp[cur.x][cur.y] == 'E')return cur.len;else if (mapp[cur.x][cur.y] == 'K')cur.hasKey = true;if (!cur.hasKey)mapp[cur.x][cur.y] = 'D';elsemapp[cur.x][cur.y] = 'W';for (int[] d : dir) {int tx = cur.x + d[0];int ty = cur.y + d[1];if (tx < 0 || tx >= n || ty < 0 || ty >= m || mapp[tx][ty] == 'W')continue;if (!cur.hasKey && mapp[tx][ty] == 'D')continue;q.add(new Node(tx, ty, cur.len + 1, cur.hasKey));}}return -1;}public static void main(String[] args) throws IOException {String[] ins = br.readLine().split(" ");n = Integer.parseInt(ins[0]);m = Integer.parseInt(ins[1]);mapp = new char[n][m];for (int i = 0; i < n; i++) {mapp[i] = br.readLine().toCharArray();}Node nd = null;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (mapp[i][j] == 'S') {nd = new Node(i, j, 0, false);q.add(nd);break;}}}int res = bfs();System.out.println(res);br.close();}
}
九、八数码问题
在一个 3×3 的网格中,1∼8 这 8个数字和一个 x
恰好不重不漏地分布在这 3×3 的网格中。
例如:
1 2 3
x 4 6
7 5 8
在游戏过程中,可以把 x
与其上、下、左、右四个方向之一的数字交换(如果存在)。
我们的目的是通过交换,使得网格变为如下排列(称为正确排列):
1 2 3
4 5 6
7 8 x
例如,示例中图形就可以通过让 x
先后与右、下、右三个方向的数字交换成功得到正确排列。
交换过程如下:
1 2 3 1 2 3 1 2 3 1 2 3
x 4 6 4 x 6 4 5 6 4 5 6
7 5 8 7 5 8 7 x 8 7 8 x
现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。
输入格式
输入占一行,将 3×3 的初始网格描绘出来。
例如,如果初始网格如下所示:
1 2 3
x 4 6
7 5 8
则输入为:1 2 3 x 4 6 7 5 8
输出格式
输出占一行,包含一个整数,表示最少交换次数。
如果不存在解决方案,则输出 −1。
输入样例:
2 3 4 1 5 x 7 6 8
输出样例
19
import java.io.*;
import java.util.*;
class Main {static void swap(char[] a, int i, int j) {char tmp = a[i];a[i] = a[j];a[j] = tmp;}static int bfs(String start, String end) {Map<String, Integer> map = new HashMap<>();Queue<String> q = new LinkedList<>();q.offer(start);map.put(start, 0);int[] dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1};while (!q.isEmpty()) {String s = q.poll();if (s.equals(end)) return map.get(s);// 获得x的位置int k = s.indexOf('x');int x = k / 3, y = k % 3;for (int i = 0; i < 4; i++) {int a = x + dx[i], b = y + dy[i];if (a < 3 && a >= 0 && b < 3 && b >= 0) {// 对字符串中的字符进行更改char[] arr = s.toCharArray();swap(arr, k, a * 3 + b);String str = new String(arr);// 如果没有被遍历过if (map.get(str) == null) {map.put(str, map.get(s) + 1);q.offer(str);} }}}return -1;}public static void main(String[] args) throws IOException {BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));String[] s = cin.readLine().split(" ");String start = "";for (int i = 0; i < s.length; i++) start += s[i];String end = "12345678x";System.out.println(bfs(start, end));}
}
十、 字符变换
[NOIP2002]字串变换
已知有两个字串 A, B及一组字串变换的规则(至多6个规则):
A1 -> B1
A2 -> B2
规则的含义为:在A中的子串 A1可以变换为 B1、A2可以变换为 B2 …。
例如:A='abcd' B='xyz'
变换规则为:
‘abc’->‘xu’ ‘ud’->‘y’ ‘y’->‘yz’
则此时,A 可以经过一系列的变换变为 B,其变换的过程为:
‘abcd’->‘xud’->‘xy’->‘xyz’
共进行了三次变换,使得A变换为B。
输入描述:
输入格式如下:
A B
A1 B1 \
A2 B2 |-> 变换规则
... ... /
所有字符串长度的上限为 20。
输出描述:
输出格式如下:
若在10步(包含 10步)以内能将A变换为B,则输出最少的变换步数;否则输出"NO ANSWER!"
示例1
输入
abcd xyz
abc xu
ud y
y yz
输出
3
import java.io.*;
import java.util.*;public class Main {static String s1,s2;static Map<String, List<String>> map = new HashMap<>();public static void main(String[] args) throws IOException {Scanner scan = new Scanner(System.in);s1 = scan.next();s2 = scan.next();while (scan.hasNext()){String key = scan.next();String val = scan.next();if(map.containsKey(key)){map.get(key).add(val);}else{List<String> list = new LinkedList<>();list.add(val);map.put(key, list);}}int b = bfs();if(b != -1){out.println(b);}else{out.println("NO ANSWER!");}out.flush();out.close();}static int bfs(){Set<String> set = new HashSet<>();Deque<String> queue = new LinkedList<>();queue.add(s1);set.add(s1);int ans = 0;while (queue.size() != 0){int si = queue.size();for (int i = 0; i < si; i++) {String poll = queue.poll();if(poll.equals(s2)){return ans;}for(String key: map.keySet()){for(String val: map.get(key)){for (int j = 0; j <= poll.length() - key.length(); j++) {if(poll.startsWith(key, j)){String str = new StringBuilder(poll).replace(j, j + key.length(), val).toString();if(!set.contains(str)){set.add(str);queue.add(str);}}}}}}ans++;if(ans > 9) return -1;}return -1;}static PrintWriter out = new PrintWriter(System.out);}