1.BFS求最短路
这个题很明显滴BFS,但需要考虑的一点就是它与输出最短距离还是有点区别的,需要输出字典序最小的路径,字典序最小我们可以通过方向向量来控制,路径我们可以在定义一个节点类的时候加上去,这样每走到一个点就会对应相应的路径!!!
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
//第十届蓝桥杯迷宫;BFS
public class Maze {
static char[][] g = new char[30][50];
static int[] dx = {1,0,0,-1};//D L R U
static int[] dy = {0,-1,1,0};
static String[] d = { "D", "L", "R", "U" };
static Queue<Node> q = new LinkedList<>();
static String ans="";
static boolean[][]st=new boolean[30][50];
public static void main(String[] args) {
String string = "01010101001011001001010110010110100100001000101010"
+"00001000100000101010010000100000001001100110100101"
+"01111011010010001000001101001011100011000000010000"
+"01000000001010100011010000101000001010101011001011"
+"00011111000000101000010010100010100000101100000000"
+"11001000110101000010101100011010011010101011110111"
+"00011011010101001001001010000001000101001110000000"
+"10100000101000100110101010111110011000010000111010"
+"00111000001010100001100010000001000101001100001001"
+"11000110100001110010001001010101010101010001101000"
+"00010000100100000101001010101110100010101010000101"
+"11100100101001001000010000010101010100100100010100"
+"00000010000000101011001111010001100000101010100011"
+"10101010011100001000011000010110011110110100001000"
+"10101010100001101010100101000010100000111011101001"
+"10000000101100010000101100101101001011100000000100" //D -> L -> R -> U
+"10101001000000010100100001000100000100011110101001"
+"00101001010101101001010100011010101101110000110101"
+"11001010000100001100000010100101000001000111000010"
+"00001000110000110101101000000100101001001000011101"
+"10100101000101000000001110110010110101101010100001"
+"00101000010000110101010000100010001001000100010101"
+"10100001000110010001000010101001010101011111010010"
+"00000100101000000110010100101001000001000000000010"
+"11010000001001110111001001000011101001011011101000"
+"00000110100010001000100000001000011101000000110011"
+"10101000101000100010001111100010101001010000001000"
+"10000010100101001010110000000100101010001011101000"
+"00111100001000010000000110111000000001000000001011"
+"10000001100111010111010001000110111010101101111000";
for (int i = 0 ; i < 30 ; i++) {
for(int j = 0 ; j < 50 ; j++) {
g[i][j] = string.charAt(i*50+j); //
}
}
bfs();
}
public static void bfs(){
q.offer(new Node(0,0,""));
st[0][0]=true;
while(!q.isEmpty()){
Node t = q.poll();
for (int i = 0; i <4 ; i++) {
int x=t.x+dx[i];
int y=t.y+dy[i];
String rode = t.Rode;
if(t.x==29&&t.y==49){
System.out.print(t.Rode);
break;
}
if(x>=0&&x<30&&y>=0&&y<50&&!st[x][y]&&g[x][y]=='0'){
st[x][y]=true;
q.offer(new Node(x,y,rode+d[i]));
}
}
}
}
public static class Node{
int x;
int y;
String Rode;
public Node(int x, int y, String rode) {
this.x = x;
this.y = y;
Rode = rode;
}
}
}
2.BFS求最少操作步数
链接:15.九宫重排 - 蓝桥云课 (lanqiao.cn)
我们都知道数字华容道吧,当然我是通过最强大脑这个节目了解的,题目的意思就是我们至少需要多少步能完成它!!!
BFS就是扩展与它相邻的点,很明显,我们可以将 . 与它周围的四个点进行交换,与最终成功的答案比较。 交换一次就得到了新的字符串,我们可以用HashMap<String,Intenger>来统计,String记录路径,Intenger记录的是经过交换得到该字符串的最小操作步数。
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class 九宫重排 {
static HashMap<String,Integer>map=new HashMap<>();
static Queue<String>q=new LinkedList<>();
static int[]dx={1,0,0,-1};
static int[]dy={0,-1,1,0};
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String start = sc.next();
String end=sc.next();
System.out.println(bfs(start,end));
}
public static int bfs(String start,String end){
q.offer(start);
map.put(start,0);
while (!q.isEmpty()){
String t = q.poll();
if(t.equals(end)){
return map.get(t);
}
int index = t.indexOf('.');
int tx=index/3;
int ty=index%3;
int step=map.get(t);
for (int i = 0; i < 4; i++) {
int x=tx+dx[i];
int y=ty+dy[i];
if(x>=0&&x<3&&y>=0&&y<3){
char[] chars = t.toCharArray();
swap(chars,x*3+y,index);
String s=new String(chars);
if(!map.containsKey(s)){
map.put(s,step+1);
q.offer(s);
}
}
}
}
return -1;
}
public static void swap(char[]Chars ,int i,int j){
char temp=Chars[i];
Chars[i]=Chars[j];
Chars[j]=temp;
}
}
3.Dijkstra算法
单源最短路用它用它用它!!!!!
import java.util.Arrays;
import java.util.Scanner;
public class Dijkstra {
static int N = 510,n,m, max = 0x3f3f3f3f;
static int[][] g = new int[N][N];//存每个点之间的距离
static int[] dist = new int[N];//存每个点到起点之间的距离
static boolean[] st = new boolean[N];//存已经确定了最短距离的点
public static int dijkstra(){
Arrays.fill(dist,max);//将dist数组一开始赋值成较大的数
dist[1] = 0; //首先第一个点是零
//从0开始,遍历n次,一次可以确定一个最小值
for(int i = 0 ; i < n ; i ++ ){
int t = -1; //t这个变量,准备来说就是转折用的
for(int j = 1 ; j <= n ; j ++ ){
/***
* 因为数字是大于1的,所以从1开始遍历寻找每个数
* 如果s集合中没有这个数
* 并且t == -1,表示刚开始 或者 后面的数比我心找的数距离起点的距离短
* 然后将j 的值赋值给 t
***/
if(!st[j] && (t == -1 || dist[j] < dist[t])){
t = j;
}
}
st[t] = true;//表示这个数是已经找到了确定了最短距离的点
//用已经确认的最短距离的点来更新后面的点
//就是用1到t的距离加上t到j的距离来更新从1到j的长度
for(int j = 1 ; j <= n ; j ++ ){
//
dist[j] = Math.min(dist[j],dist[t] + g[t][j]);
}
}
//如果最后n的长度没有改变,输出-1,没有找到;否则输出最短路n
if(dist[n] == max) return -1;
else return dist[n];
}
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
m = scan.nextInt();
//将他们每个点一开始赋值成一个较大的值
for(int i = 1 ; i <= n ; i ++ ){
Arrays.fill(g[i],max);
}
while(m -- > 0){
int a = scan.nextInt();
int b = scan.nextInt();
int c = scan.nextInt();
g[a][b] = Math.min(g[a][b],c);//这个因为可能存在重边,所以泽出最短的
}
int res = dijkstra();
System.out.println(res);
}
}
4.Floyd算法
多源最短路用它用它用它!!!!
import java.util.Scanner;
public class Floyd {
static int N = 210,n,m,k,INF = 0x3f3f3f3f;
static int[][] g = new int[N][N];
/***floyd算法只需要三重循环就可以解决问题,hh《很简单》
* g[i,j,k] = min(g[i,j,k-1],g[i,k,k-1]+g[k,j,k-1]);
* 原状态是:f[i, j, k]表示从i走到j的路径上除了i, j以外不包含点k的所有路径的最短距离。
* 那么f[i, j, k] = min(f[i, j, k - 1), f[i, k, k - 1] + f[k, j, k - 1]。
* 因此在计算第k层的f[i, j]的时候必须先将第k - 1层的所有状态计算出来,所以需要把k放在最外层。
*
* 这里其实就是将所有k的可能性已经·存好,等待你输入就OK了
***/
public static void floyd(){
for(int k = 1 ; k <= n ; k ++ ){
for(int i = 1 ; i <= n ; i ++ ){
for(int j = 1 ; j <= n ; j ++ ){
g[i][j] = Math.min(g[i][j],g[i][k] + g[k][j]);
}
}
}
}
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
m = scan.nextInt();
k = scan.nextInt();
for(int i = 1 ; i <= n ; i ++ ){
for(int j = 1 ; j <= n ; j ++ ){
if(i == j) g[i][j] = 0; //可能存在询问自身到自身的距离,所以需要存0
else g[i][j] = INF; //然后其他都可以存成INF最大值
}
}
while(m -- > 0 ){
int a = scan.nextInt();
int b = scan.nextInt();
int c = scan.nextInt();
g[a][b] = Math.min(g[a][b],c); //这里可能存在重边,取最小的边
}
floyd();
while(k -- > 0){
int x = scan.nextInt();
int y = scan.nextInt();
int t = g[x][y];
//这里可能最后到不了目标点,但是可能路径上面存在负权边,然后将目标点更新了,所以不是到底== INF
if(t > INF / 2) System.out.println("impossible");
else System.out.println(t);
}
}
}
5.图的存储
图的存储方式有邻接矩阵和邻接表两种。
邻接矩阵很简单,下面重要说一下邻接表的模拟实现。
static int[]h=new int[N],e=new int[N],ne=new int[N];
static int idx;
public static void add(int a,int b,int c){
e[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx++;
}
6.拓扑排序
import java.util.*;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
public static int N = 100010, idx = 0, n, m;
public static int[] h = new int[N], e = new int[N], ne = new int[N];
public static int[] d = new int[N];
static ArrayList<Integer>list=new ArrayList<>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
Arrays.fill(h, -1);
for (int i = 0; i < m; i++){
int a = sc.nextInt(), b = sc.nextInt();
add(a, b);
}
top_sort();
}
public static void add(int a, int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
d[b]++;
}
public static void top_sort(){
Queue<Integer> q = new LinkedList<>();
for (int i = 1; i <= n; i++) {
if (d[i] == 0) q.add(i);
}
while (!q.isEmpty()) {
int t = q.poll();
list.add(t);
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
d[j]--;
if (d[j] == 0) q.offer(j);
}
}
if(list.size()==n){
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i)+" ");
}
}else{
System.out.println(-1);
}
}
}