目录
844. 走迷宫 - BFS求最短路
1233. 全球变暖 - BFS
845. 八数码 - 最短路BFS + 状态表示 + 一二维坐标转换
为什么BFS保证走的是最短路?
一二维坐标转换(n×n矩阵)
1562.微博转发 - BFS按层遍历 + 有向图
844. 走迷宫 - BFS求最短路
活动 - AcWing
题目:
思路:
为什么就算有多条通路,它总能输出最小距离?
因为当第一个点到达终点时,它一定是最短距离,并且会将终点标记,那么其他点再也无法到达终点,也更新不了初始点到终点的距离将起点(0,0)入队,上下左右走,只要在合法的范围内且不碰到墙且没有走过,则入队
BFS就是将所有能走的路都走,第一条能走通的路一定是最短路
/*
*道阻且长,行则将至*
author:Roye_ack
*/
import java.util.*;
import java.io.*;
import java.math.*;
class Main
{
static int N=300010;
static int[][] g=new int[110][110];
static int[][] d=new int[110][110]; //记录该点到起点的距离
static int[][] st=new int[110][110];
static int[] dx={-1,1,0,0};
static int[] dy={0,0,-1,1};
static int n,m;
public static int bfs()
{
d[0][0]=0;
Queue<PII> q=new LinkedList<>();
q.offer(new PII(0,0));
while(!q.isEmpty())
{
PII t=q.poll();
for(int i=0;i<4;i++)
{
int nx=t.x+dx[i];
int ny=t.y+dy[i];
if(nx>=0&&nx<n&&ny>=0&&ny<m&&g[nx][ny]==0&&st[nx][ny]==0)
{
q.offer(new PII(nx,ny));
d[nx][ny]=d[t.x][t.y]+1;
st[nx][ny]=1;
}
}
}
return d[n-1][m-1];
}
public static void main(String[] args) throws IOException
{
PrintWriter wt=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
n=rd.nextInt();
m=rd.nextInt();
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
g[i][j]=rd.nextInt();
wt.print(bfs());
wt.flush();
}
static class rd
{
static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tk=new StringTokenizer("");
static String nextLine() throws IOException
{
return bf.readLine();
}
static String next() throws IOException
{
while(!tk.hasMoreTokens()) tk=new StringTokenizer(bf.readLine());
return tk.nextToken();
}
static int nextInt() throws IOException
{
return Integer.parseInt(next());
}
static double nextDouble() throws IOException
{
return Double.parseDouble(next());
}
static long nextLong() throws IOException
{
return Long.parseLong(next());
}
static BigInteger nextBig() throws IOException
{
BigInteger d=new BigInteger(rd.nextLine());
return d;
}
}
}
class PII
{
int x,y;
PII(int x,int y)
{
this.x=x;
this.y=y;
}
}
1233. 全球变暖 - BFS
活动 - AcWing
题目:
.表示海洋,#表示陆地
....... .##.... .##.... ....##. ..####. ...###. .......
如果陆地的上下左右存在海洋,则该陆地被淹没
问有多少个岛屿会被完全淹没?
思路:
- 遍历岛屿,从某块陆地入手开始bfs, 统计该岛屿的陆地总数total以及被淹没的陆地数submerge
- 如果岛屿陆地总数==被淹没的陆地数,说明这个岛屿完全被淹没,则res++
- 走过的陆地要标记,避免重复遍历
/*
*道阻且长,行则将至*
author:Roye_ack
*/
import java.util.*;
import java.io.*;
import java.math.*;
class Main
{
static int N=1010;
static char[][] g=new char[N][N];
static int[][] st=new int[N][N];
static int[] dx={-1,1,0,0};
static int[] dy={0,0,-1,1};
static int n;
public static boolean bfs(int x,int y)
{
Queue<PII> q=new LinkedList<>();
q.offer(new PII(x,y));
st[x][y]=1;
int total=0; //统计遍历的陆地数
int submerge=0; //统计被淹没的陆地数
while(!q.isEmpty())
{
var t=q.poll();
total++;
boolean f=false; //f判断该陆地是否被淹没
for(int i=0;i<4;i++)
{
int nx=t.x+dx[i];
int ny=t.y+dy[i];
if(nx<0||nx>=n||ny<0||ny>=n) continue;
if(st[nx][ny]==1) continue;
if(g[nx][ny]=='.') //如果当前陆地上下左右存在海,则该陆地被淹没
{
f=true;
continue;
}
st[nx][ny]=1;
q.offer(new PII(nx,ny));
}
if(f) submerge++;
}
return total==submerge;
}
public static void main(String[] args) throws IOException
{
PrintWriter wt=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
n=rd.nextInt();
int res=0;
for(int i=0;i<n;i++)
{
String s=rd.next();
for(int j=0;j<n;j++)
g[i][j]=s.charAt(j);
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(g[i][j]=='#'&&st[i][j]==0) //遍历岛屿
{
if(bfs(i,j)) res++;
}
wt.print(res);
wt.flush();
}
static class rd
{
static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tk=new StringTokenizer("");
static String nextLine() throws IOException
{
return bf.readLine();
}
static String next() throws IOException
{
while(!tk.hasMoreTokens()) tk=new StringTokenizer(bf.readLine());
return tk.nextToken();
}
static int nextInt() throws IOException
{
return Integer.parseInt(next());
}
static double nextDouble() throws IOException
{
return Double.parseDouble(next());
}
static long nextLong() throws IOException
{
return Long.parseLong(next());
}
static BigInteger nextBig() throws IOException
{
BigInteger d=new BigInteger(rd.nextLine());
return d;
}
}
}
class PII
{
int x,y;
PII(int x,int y)
{
this.x=x;
this.y=y;
}
}
845. 八数码 - 最短路BFS + 状态表示 + 一二维坐标转换
活动 - AcWing
题目:
给你一个3×3的华容道
1 2 3 x 4 6 7 5 8
x可以跟上下左右的数字进行交换
问移动到最后状态↓的最小步数是多少?
1 2 3 4 5 6 7 8 x
思路:
BFS求最短路,将x往上下左右四个方向走,如果之前不存在这种情况则步数在之前的基础上+1,BFS保证走的是最短路
为什么BFS保证走的是最短路?
因为BFS是一层层的搜索,假设边的权值都是1,那么每搜一次(即入队一层),路径长度+1,所以最先到终点的那条路径一定是最短的,而且因为走过的点有标记,所以每个点只会遍历一次,则遍历结束后就能知道最短路,所以用BFS可以求任意起点到终点的最短路径
我们可以将3×3矩阵的状态压缩成一维的
x=idx/3 y=idx%3
用map储存 mp<string状态,int路径长度>
对于每一个状态,我们将x上下左右移动,直到搜索到答案 "12345678x"
一二维坐标转换(n×n矩阵)
设idx为一维坐标
一维→二维
x=idx/n; y=idx%n;
二维→一维
idx=x*n+y;
/*
*道阻且长,行则将至*
author:Roye_ack
*/
import java.util.*;
import java.io.*;
import java.math.*;
class Main
{
static int N=100010;
static int[] dx={0,0,1,-1};
static int[] dy={1,-1,0,0};
static void swap(char[] a,int idx1,int idx2)
{
char t=a[idx1];
a[idx1]=a[idx2];
a[idx2]=t;
}
static int bfs(String start)
{
Queue<String> q=new LinkedList<>();
Map<String,Integer> mp=new HashMap<>();
String end="12345678x";
q.offer(start);
mp.put(start,0);
while(!q.isEmpty())
{
var t=q.poll();
if(t.equals(end)) return mp.get(t);
int idx=t.indexOf('x');
int x=idx/3,y=idx%3; //将x的一维下标转换成二维
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx<0||nx>=3||ny<0||ny>=3) continue;
char[] temp=t.toCharArray();
swap(temp,idx,nx*3+ny); //交换位置
String s=String.valueOf(temp);
if(!mp.containsKey(s)) //如果之前没有走过这一步 则步数+1
{
mp.put(s,mp.getOrDefault(t,0)+1);
q.offer(s);
}
}
}
return -1;
}
public static void main(String[] args) throws IOException
{
PrintWriter wt=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
String[] ss=rd.nextLine().split(" ");
String start="";
for(int i=0;i<ss.length;i++) start+=ss[i];
wt.print(bfs(start));
wt.flush();
}
static class rd
{
static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tk=new StringTokenizer("");
static String nextLine() throws IOException
{
return bf.readLine();
}
static String next() throws IOException
{
while(!tk.hasMoreTokens()) tk=new StringTokenizer(bf.readLine());
return tk.nextToken();
}
static int nextInt() throws IOException
{
return Integer.parseInt(next());
}
static double nextDouble() throws IOException
{
return Double.parseDouble(next());
}
static long nextLong() throws IOException
{
return Long.parseLong(next());
}
static BigInteger nextBig() throws IOException
{
BigInteger d=new BigInteger(rd.nextLine());
return d;
}
}
}
1562.微博转发 - BFS按层遍历 + 有向图
https://www.acwing.com/problem/content/1564/
题目:
第一行给出n(n个用户) l(需要考虑的层数)
接下来n行格式:m——第i名用户关注的总人数 mi——这位用户关注的用户编号
最后有q个询问,问qi用户最大可能关注量
如果 B 是 A 的关注者,C 是 B 的关注者,那么 A 的第一层关注者是 B,第二层关注者是 C
思路:
对于每一个用户i,建立一个有向图
bfs遍历l层,遍历过用户的做标记 ,统计l层内未被标记的用户个数,即最大转发量
/*
*道阻且长,行则将至*
author:Roye_ack
*/
import java.util.*;
import java.io.*;
import java.math.*;
class Main
{
static int N=1010,M=100010;
static int[] h=new int[N],ne=new int[M],e=new int[M];
static int idx,n,l;
public static void add(int a,int b)
{
e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
public static int bfs(int x)
{
int[] st=new int[N];
Queue<Integer> q=new LinkedList<>();
q.offer(x);
st[x]=1;
int res=0;
for(int k=0;k<l;k++)
{
int sz=q.size();
while(sz-->0)
{
var t=q.poll();
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(st[j]==0)
{
st[j]=1;
q.offer(j);
res++;
}
}
}
}
return res;
}
public static void main(String[] args) throws IOException
{
PrintWriter wt=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
n=rd.nextInt();
l=rd.nextInt();
Arrays.fill(h,-1);
for(int i=1;i<=n;i++)
{
int cnt=rd.nextInt();
while(cnt-->0)
{
int x=rd.nextInt();
add(x,i);
}
}
int q=rd.nextInt();
while(q-->0)
{
int t=rd.nextInt();
wt.println(bfs(t));
}
wt.flush();
}
static class rd
{
static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tk=new StringTokenizer("");
static String nextLine() throws IOException
{
return bf.readLine();
}
static String next() throws IOException
{
while(!tk.hasMoreTokens()) tk=new StringTokenizer(bf.readLine());
return tk.nextToken();
}
static int nextInt() throws IOException
{
return Integer.parseInt(next());
}
static double nextDouble() throws IOException
{
return Double.parseDouble(next());
}
static long nextLong() throws IOException
{
return Long.parseLong(next());
}
static BigInteger nextBig() throws IOException
{
BigInteger d=new BigInteger(rd.nextLine());
return d;
}
}
}
/*class PII
{
int x,y;
PII(int x,int y)
{
this.x=x;
this.y=y;
}
}*/