链接:搜索专题-前15题
密码:202201110000
1)BFS&DFS的区别
2)两种算法基础讲解
3)BFS 模板总结及例题详解
4) 【算法入门】广度/宽度优先搜索(BFS)
5)深度优先是否需要回溯的情形
6)dfs中return回溯问题
7)回溯算法
8)双向搜索
文中代码代入 核心代码区 即可运行
import java.io.*;
import java.util.*;
public class Main {
static class FastReader{
BufferedReader br;
StringTokenizer st;
public FastReader(){br=new BufferedReader(new InputStreamReader(System.in));}
String next(){
while (st==null||!st.hasMoreElements()) {
try {st = new StringTokenizer(br.readLine());}
catch (IOException e) {e.printStackTrace();}}
return st.nextToken();}
int nextInt(){return Integer.parseInt(next());}
boolean hasNext(){
if (st!=null && st.hasMoreTokens())
return true;
try {
st=new StringTokenizer(br.readLine());
} catch (Exception e) {
return false;
}
return true;
}
}
static PrintWriter out=new PrintWriter(
new BufferedWriter(new OutputStreamWriter(System.out)));
/*
核心代码区
*/
}
题目链接:POJ1321
static int n,k,sum,cnt;//棋盘大小,摆放棋子数目,方案数,当前已摆放棋子数目
static int vis[];//标记该位置是否访问过
static char map[][];//存储棋盘内容
public static void main(String[] args) throws IOException{
FastReader sc=new FastReader();//创建快输对象
while(true){
n=sc.nextInt();
k=sc.nextInt();
if(n==-1&&k==-1)break;//结束循环
vis=new int[n];
map=new char[n][n];
for(int i=0;i<n;i++){
map[i]=sc.next().toCharArray();
}
for(int i=0;i<n;i++)vis[i]=0;
sum=cnt=0;
dfs(0);
System.out.println(sum);;
}
}
public static void dfs(int row){//按行递归
//已摆放k个棋子,总方案数+1
if(cnt==k){sum++;return;}
//临界情况
if(row<0||row>=n)return;
for(int i=0;i<n;i++){//标记列
if(vis[i]==0&&map[row][i]=='#') {
vis[i]=1;
cnt++;
dfs(row+1);
//要统计所有你可行方案,回溯
vis[i]=0;
cnt--;
}
}
//从第row+1行再次递归
dfs(row+1);
}
题目链接:洛谷P2036
static int n,ans=2147483647;//配料数量,最终结果(取最小值)
static int a[],b[];//酸度&苦度
public static void main(String[] args) throws IOException{
FastReader sc=new FastReader();
n=sc.nextInt();
a=new int[n];
b=new int[n];
for(int i=0;i<n;i++){
a[i]=sc.nextInt();
b[i]=sc.nextInt();
}
dfs(0,1,0);
System.out.println(ans);
}
public static void dfs(int idx,int x,int y){//按行递归
//i是表示目前的配料编号,x为酸度,y为甜度
if(idx>=n){
//遇到特殊情况回溯,该特殊情况即为初始值
if(x==1&&y==0)return;
ans=Math.min(Math.abs(x-y),ans);
return;
}
//分两种情况搜索:1添加 2不添加
//这样无需回溯
dfs(idx+1,x*a[idx],y+b[idx]);
dfs(idx+1,x,y);
}
题目链接:POJ NOI0202-1750
//字符数组升序存储,按下标的全排列进行输出
static int pd[],used[];//判断某下标是否已使用,存储当前方案的一个排列
static int n;//该字符串的长度
static char c[];//存储字符数组
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FastReader sc=new FastReader();
c=(sc.next()).toCharArray();
Arrays.sort(c);//字符按字典序升序排列
n=c.length;
pd=new int[n];
used=new int[n];
for(int i=0;i<n;i++)pd[i]=0;
dfs(0);
out.flush();
}
static void dfs(int k) {//k为选择的第几个数字
if(k>=n) {//已选择n个数字,则输出该排列
for(int i=0;i<n;i++)out.print(c[used[i]]);
out.println();out.flush();
return;
}
else {
for(int i=0;i<n;i++) {
if(pd[i]==0) {
pd[i]=1;used[k]=i;
dfs(k+1);
//遍历所有方案,回溯
pd[i]=0;
}
}
}
}
题目链接:计蒜客 T1248
static int n0,n,cnt=0;//n0接收要拆分的数,n用来存n0还未拆分的部分,cnt记录最新拆分的数的下标
static int ans[];//记录拆分的数
public static void main(String[] args) {
// TODO Auto-generated method stub
FastReader sc=new FastReader();
n0=sc.nextInt();
n=n0;
ans=new int[n+1];
dfs(1);//从1开始拆
out.flush();
}
static void dfs(int last) {//last表示上次拆分的数
//临界情况:排除直接输出n0的情况
if (cnt==1&&n==0) return;
//n0拆分完毕,直接输出
if (n==0) {
out.print(n0+"=");
for(int i=1;i<cnt;i++)out.print(ans[i]+"+");
out.printf("%d\n",ans[cnt]);
return;
}
//从上次拆分的数开始枚举
for (int i=last;i<=n;i++) {
ans[++cnt]=i;
n-=i;//更新n
dfs(i);
//回溯
cnt--;n+=i;
}
}
题目链接:HDU1016
题目翻译:vjudge
static int n,cnt1,cnt2;//cnt1记录case数,cnt2判断case内是否需要换行
static boolean vis[]=new boolean[25];//vis标记数字
static int ans[]=new int[25];//ans记录序列
static int isprime[]={0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,
0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0};//isprime判断素数(0~39)
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FastReader sc=new FastReader();
cnt1=0;
while(sc.hasNext()){
if(cnt1>=1)out.println();
out.printf("Case %d:\n",++cnt1);
n=sc.nextInt();
Arrays.fill(vis, false);
Arrays.fill(ans, 0);
ans[1]=1;
cnt2=0;
dfs(2);//从2开始,第一个数为1
out.println();out.flush();//每个case后换行
}
}
static void dfs(int x) {
if(x>n){//x=n还需判断,大于n则输出
if(isprime[ans[x-1]+1]==1){//首尾之和为素数
if(cnt2==0)cnt2=1;
else out.println();
out.print(ans[1]);
for(int i=2; i<=n; i++)
out.printf(" %d",ans[i]);
}
return ;
}
for(int i=2;i<=n;i++){
if(!vis[i]&&isprime[i+ans[x-1]]==1){//判断该数与上一个数是否为素数
vis[i]=true;
ans[x]=i;
dfs(x+1);
//遍历所有方案,回溯
vis[i]=false;
}
}
}
题目链接:HDU1312
题目翻译:vjudge
static int n,m,ans=0,stx,sty;//行和列,经过磁转总数,初始位置
static char mp[][];//存储地图
static int dx[]=new int[]{0,0,1,-1};//移动方向
static int dy[]=new int[]{1,-1,0,0};
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FastReader sc=new FastReader();
while(true){
ans=0;
m=sc.nextInt();
n=sc.nextInt();
if(n==0&&m==0)break;
mp=new char[n][m];
for(int i=0;i<n;i++){
mp[i]=(sc.next()).toCharArray();
for(int j=0;j<m;j++){
if(mp[i][j] == '@'){
stx = i;
sty = j;
mp[i][j] = '.';//初始位置也计入总数
}
}
}
dfs(stx,sty);
out.println(ans);
out.flush();
}
}
static void dfs(int x,int y) {
if(x<0||x>=n||y<0||y>=m||mp[x][y]!='.')
return;
else{//满足条件
ans++;
mp[x][y]='#';
}
for(int i = 0; i < 4; i++){
dfs(x+dx[i],y+dy[i]);
}
}
题目链接:POJ1915
题目翻译:vjudge
//骑士类
class node{
int x,y,step;
public node(int x,int y,int step){
this.x=x;this.y=y;this.step=step;
}
}
//核心代码
static int t,n,sx,sy,ex,ey;//骑士数量,棋盘大小
static int dx[]=new int[]{-1,-1,1,1,-2,-2,2,2};
static int dy[]=new int[]{2,-2,2,-2,1,-1,1,-1};
static int vis[][];//该位置是否已访问
static node q[]=new node[100005];//存储所有状态下的骑士
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FastReader sc=new FastReader();
t=sc.nextInt();
while(t-->0){
n=sc.nextInt();
sx=sc.nextInt();sy=sc.nextInt();//初始位置
ex=sc.nextInt();ey=sc.nextInt();//终点位置
vis=new int[n][n];
for(int i=0;i<n;i++)
Arrays.fill(vis[i],0);
bfs(sx,sy,ex,ey);
}
}
//广搜找最优解
static void bfs(int sx,int sy,int ex,int ey) {
int head=1,tail=1;
vis[sx][sy]=1;
q[tail]=new node(sx,sy,0);
tail++;
while(head<tail)
{
int x=q[head].x;
int y=q[head].y;
int step=q[head].step;
//找到即为最优解(step值最小)
if(x==ex&&y==ey)
{
out.printf("%d\n",step);out.flush();
break;
}
for(int i=0;i<8;i++)//注意有八个方向
{
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=0&&nx<n&&ny>=0&&ny<n&&vis[nx][ny]==0)
{
vis[nx][ny]=1;
q[tail]=new node(nx,ny,step+1);
tail++;
}
}
head++;
}//end while
}
题目链接:HDU1241
题目翻译:vjudge
static int n,m,ans;//行和列,油层数
static char mp[][];
//搜索方向
static int dir[][]={{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FastReader sc=new FastReader();
while(true){
ans=0;
n=sc.nextInt();
m=sc.nextInt();
if(n==0)break;
mp=new char[n][m];
for(int i=0;i<n;i++)
mp[i]=(sc.next()).toCharArray();
for(int i=0;i<n;i++)//逐个油层查找
for(int j=0;j<m;j++)
{
if(mp[i][j]=='@')//遇到口袋进行搜索
{
dfs(i,j);
ans++;//深搜到底后,油层数目增加
}
}
out.println(ans);out.flush();
}
}
public static void dfs(int x,int y){
if(mp[x][y]=='@')//标记搜索过的pocket
mp[x][y]='*';//该油层的pocket都进行替换
for(int i=0;i<8;i++)//八个方向搜索
{
int a=dir[i][0]+x;//横坐标改变
int b=dir[i][1]+y;//纵坐标
if(a<n&&a>=0&&b<m&&b>=0&&mp[a][b]=='@')//如果是pocket且横纵坐标都在范围内
dfs(a,b);//进行搜索
}
}
题目链接:POJ2386
题目翻译:vjudge
static int n,m,ans=0;//农田大小,水田总数
static char mp[][];//存储图
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FastReader sc=new FastReader();
n=sc.nextInt();
m=sc.nextInt();
mp=new char[n][m];
for(int i=0;i<n;i++){
mp[i]=(sc.next()).toCharArray();
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
//每一次搜索将联通的一片区域转为旱地
if(mp[i][j]=='W'){
ans++;//有水方格,结果就+1
dfs(i,j);//搜索该点的八个方向
}
}
}
out.println(ans);out.flush();
}
public static void dfs(int x,int y){
int i,j,nx,ny;
for(i=-1;i<=1;i++){
for(j=-1;j<=1;j++){
nx=x+i;//横坐标
ny=y+j;//纵坐标
if(nx>=0&&nx<n&&ny>=0&&ny<m&&mp[nx][ny]=='W')
{
mp[nx][ny]='.';//如果该点是'W'的话,就令该点是 '.' 以后也不访问它
dfs(nx,ny);// 去搜索该点
}
}
}
}
题目链接:51nod 1591
//节点类
class Node{
int l,r;//左右节点编号
public Node(int l,int r){
this.l=l;this.r=r;
}
}
//核心代码
static int n;一共n个节点
static Node btree[];//存储二叉树
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FastReader sc=new FastReader();
n=sc.nextInt();
btree=new Node[n+1];
for(int i=1;i<=n;i++){//下标从1开始
int l=sc.nextInt();
int r=sc.nextInt();
btree[i]=new Node(l,r);
}
preorder(1);//从根节点开始遍历,编号为1的节点为根节点
}
//前序遍历:根左右
public static void preorder(int x){
if(x==0)return;
out.println(x);out.flush();//访问当前节点,即输出该结点编号
preorder(btree[x].l);//遍历左子树
preorder(btree[x].r);//遍历右子树
}
题目链接:计蒜客 T1595
static int n,m;//地图大小
static boolean f=false;//判断有无通路
static char mp[][];//存储图
static int dx[]={0,0,1,-1};//搜索方向
static int dy[]={1,-1,0,0};
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FastReader sc=new FastReader();
n=sc.nextInt();
m=sc.nextInt();
mp=new char[n][m];
int sx=0,sy=0;//初始位置
for(int i=0;i<n;i++){
mp[i]=(sc.next()).toCharArray();
for(int j=0;j<m;j++){
if(mp[i][j]=='S'){
sx=i;
sy=j;
//起始点也标记为通路
mp[i][j]='.';
}
}
}
dfs(sx,sy);
if(f)out.println("yes");
else out.println("no");
out.flush();
}
public static void dfs(int x,int y){
//临界情况排除
if (x<0||x>=n||y<0||y>=m||mp[x][y]=='*')return;
//搜索到目标直接返回
if (mp[x][y] == 'T') {
f=true;
return;
}
mp[x][y]='*';//经过该点标记为'*'
for(int i=0;i<4;i++){
int nx=x+dx[i];
int ny=y+dy[i];
dfs(nx,ny);
}
}
题目链接:NOI8465
static int t,n,m,x,y,res,sum;//结果数,棋盘总点数
static int vis[][];
static int dx[]={-1,-2,-2,-1,1,2,2,1};
static int dy[]={2,1,-1,-2,2,1,-1,-2};
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FastReader sc=new FastReader();
t=sc.nextInt();
while(t-->0){
res=0;
n=sc.nextInt();m=sc.nextInt();//棋盘大小
x=sc.nextInt();y=sc.nextInt();//初始位置
vis=new int[n][m];
for(int i=0;i<n;i++)
Arrays.fill(vis[i],0);
vis[x][y]=1;
sum=n*m;
dfs(x,y,1);
out.println(res);out.flush();
}
}
public static void dfs(int x,int y,int num){
//走完了棋盘所有的点
if(num>=sum)res++;
for(int i=0;i<8;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=0&&nx<n&&ny>=0&&ny<m&&vis[nx][ny]==0){
vis[nx][ny]=1;
dfs(nx,ny,num+1);
//回溯,遍历所有走法
vis[nx][ny]=0;
}
}
}
题目链接:计蒜客
static int t,sum,ans,cnt=0;//棋盘数,当前结果,最终结果,record数组行下标
static int a[]=new int[20],b[]=new int[20],
c[]=new int[20],d[]=new int[20];//行,列,对角线,反对角线
static int mp[][]=new int[9][9];//存棋盘
static int record[][]=new int[100][10];//总共92种结果
public static void main(String[] args) {
// TODO Auto-generated method stub
FastReader sc=new FastReader();
t=sc.nextInt();
dfs(1);//得到所有结果
while(t-->0){
ans=-1;
for(int i=1;i<=8;i++){
for(int j=1;j<=8;j++){
mp[i][j]=sc.nextInt();
}
}
int k=1;
for(int i=1;i<=cnt;i++){
k=1;sum=0;
for(int j=1;j<=8;j++){
sum+=mp[k++][record[i][j]];
}
ans=Math.max(ans,sum);
}
out.println(ans);out.flush();
}
}
public static void dfs(int k){//第k行
if(k>8){
Record();return;
}
else{
for(int i=1;i<=8;i++){
if(b[i]==0&&c[k+i]==0&&d[k+8-i]==0){
a[k]=i;//标记第k行取第i个数
b[i]=1;c[k+i]=1;d[k+8-i]=1;
dfs(k+1);
b[i]=0;c[k+i]=0;d[k+8-i]=0;
}
}
}
}
public static void Record(){
cnt++;//行下标从1开始
for(int i=1;i<=8;i++){
record[cnt][i]=a[i];
}
}
题目链接:洛谷P1036
思路来源1:洛谷题解1
思路来源2:洛谷题解2
方法一:每选择一个数,计数器自增1,遍历所有可能。个人感觉更好理解。
static int n,k,ans=0;//共n个数,选k个,和为素数的种类数
static int a[];//存储数列
public static void main(String[] args) {
// TODO Auto-generated method stub
FastReader sc=new FastReader();
n=sc.nextInt();
k=sc.nextInt();
a=new int[n];
for(int i=0;i<n;i++)a[i]=sc.nextInt();
dfs(0,0,0);
out.println(ans);
out.flush();
}
static void dfs(int cnt,int sum,int start){
//cnt代表现在选择了多少个数
//sum表示当前的和
//start表示升序排列,以免算重
if(cnt==k){//选完了
if(isprime(sum))ans++;//和为素数,结果+1
return ;
}
for(int i=start;i<n;i++)
dfs(cnt+1,sum+a[i],i+1);
//步数要加一,和也要加
//升序起始值要变成i+1,以免算重
return ;//到这一步,枚举完毕,返回
}
static boolean isprime(int n){//判断是否为质数
for(int i=2;i*i<=n;i++){
if(n%i==0)return false;
}
return true;
}
方法二:一种更加简洁的dfs算法,时间与空间复杂度和第一种差不多
static int n,k,ans=0;
static int a[];
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FastReader sc=new FastReader();
n=sc.nextInt();
k=sc.nextInt();
a=new int[n];
for(int i=0;i<n;i++)a[i]=sc.nextInt();
out.println(dfs(k,0,0,n-1));
out.flush();
}
static int dfs(int k,int sum,int start,int end){
//k为还需要选中的个数,sum为前面累加的和
//start和end为全组合剩下数字的选取范围;调用递归生成全组合
//在过程中逐渐把K个数相加,当选取的数个数为0时,直接返回前面的累加和是否为质数即可
if(k==0)return isprime(sum)?1:0;
int cnt=0;
for(int i=start;i<=end;i++){
cnt+=dfs(k-1,sum+a[i],i+1,end);
}
return cnt;
}
static boolean isprime(int n){//判断是否质数
for(int i=2;i*i<=n;i++){
if(n%i==0)return false;
}
return true;
}
题目链接:洛谷P4667
题目翻译:vjudge
思路来源:洛谷题解
思路总结:BFS&双端队列
JAVA版:洛谷有两个点TLE
//dx和dy是点的方向数组
static int dx[]={1,-1,-1,1};
static int dy[]={1,1,-1,-1};
//字符数组表示电线在各个方向的状态
static char a[]=new String("\\/\\/").toCharArray();
//ix和iy是格子的方向数组
static int ix[]={0,-1,-1,0};
static int iy[]={0,0,-1,-1};
//双端队列,分别存横纵坐标
static Deque<Integer> x=new ArrayDeque<>();
static Deque<Integer> y=new ArrayDeque<>();
static char map[][]=new char[505][505]; //存储地图
static int vis[][]=new int[505][505]; //vis数组,记录最短步数
static int l,c; //l——line(行数),c——column(列数)
static int inf=1061109567;
public static void main(String[] args) {
FastReader sc=new FastReader();
//输入
l=sc.nextInt();
c=sc.nextInt();
for(int i=0;i<l;i++)
map[i]=(sc.next()).toCharArray();
/*
沿对角线走的时候,坐标之和的奇偶性是不变的
从(0,0)出发,横纵坐标和是偶数,
所以只要终点的横纵坐标和是奇数,那必定 NO SOLUTION.
*/
if((l+c)%2==1) //如果终点横纵坐标和是奇数
out.printf("NO SOLUTION\n");//那就铁定无解
else {
bfs(); //不无解那就广搜
out.println(vis[l][c]); //输出最后的步数
}
out.flush();
}
static void bfs(){ //广搜函数
for(int i=0;i<vis.length;i++)
//因为要求最小值,把vis数组初始化成一个很大的数
Arrays.fill(vis[i],inf);
x.offerLast(0); //起点(0,0)入队,步数是0
y.offerLast(0);
vis[0][0]=0;
while(!x.isEmpty()){ //这一部分就是把广搜模板
/*
只有新算出来的步数比原来的少的时候,才能入队
当get到队首顶点的时候,要先把它pop出去
否则元素从队首入队,刚进去就出来了,程序就会反复搜同一个点,导致死循环
*/
int xx=x.pollFirst(); //先get到队首,一定要get完了之后先pop出去
int yy=y.pollFirst();
for(int i=0;i<4;i++){ //4个方向一个一个试
int dnx=xx+dx[i]; //dnx,dxy——点的横纵坐标
int dny=yy+dy[i];
int inx=xx+ix[i];//inx,iny——格子的横纵坐标
int iny=yy+iy[i];
if(dnx>=0&&dnx<=l&&dny>=0&&dny<=c){ //如果没出界的话就考虑入不入队
if(a[i]!=map[inx][iny]){ //判断地图的电线状态和往这个方向走的电线状态是否一致
int t=vis[xx][yy]+1; //不一致就要转向,步数+1
if(t<vis[dnx][dny]){ //如果比原来的步数小,就入队,标记
x.offerLast(dnx); //转向肯定不如不转向好,所以要后搜,从队尾入队
y.offerLast(dny);
vis[dnx][dny]=t;
}
}
else{//不用转向
int t=vis[xx][yy]; //不用转向,步数不用变;
if(t<vis[dnx][dny]){ //步数比原来的小才能入队
x.offerFirst(dnx); //不用转向肯定更好,要先搜,从队首入队
y.offerFirst(dny);
vis[dnx][dny]=t;
}
}
}
}
}
}
C++版:原版代码
#include
#include
#include
using namespace std;
const int dx[4]={1,-1,-1,1};
const int dy[4]={1,1,-1,-1};
const char a[5]="\\/\\/";
const int ix[4]={0,-1,-1,0};
const int iy[4]={0,0,-1,-1};
deque <int> x;
deque <int> y;
char map[505][505];
int vis [505][505];
int l,c;
void bfs(){
memset(vis,0x3f,sizeof(vis));
x.push_back(0);
y.push_back(0);
vis[0][0]=0;
while(!x.empty()){
int xx=x.front();
int yy=y.front();
x.pop_front();
y.pop_front();
for(int i=0;i<4;i++){
int dnx=xx+dx[i];
int dny=yy+dy[i];
int inx=xx+ix[i];
int iny=yy+iy[i];
if(dnx>=0&&dnx<=l&&dny>=0&&dny<=c){
if(a[i]!=map[inx][iny]){
int t=vis[xx][yy]+1;
if(t<vis[dnx][dny]){
x.push_back(dnx);
y.push_back(dny);
vis[dnx][dny]=t;
}
}
else{
int t=vis[xx][yy];
if(t<vis[dnx][dny]){
x.push_front(dnx);
y.push_front(dny);
vis[dnx][dny]=t;
}
}
}
}
}
}
int main()
{
cin>>l>>c;
for(int i=0;i<l;i++)
cin>>map[i];
if((l+c)%2)
cout<<"NO SOLUTION\n";
else {
bfs();
cout<<vis[l][c]<<endl;
}
return 0;
}
题目链接:洛谷P1101
static int record[][];//存'y'的下标
static boolean pd[][];//判断是否为'yizhong'
static char mp[][];//存地图
static char ch[]="yizhong".toCharArray();//存"yizhong"字符
static int dir[][]={{0,1},{0,-1},{1,0},{-1,0},
{1,1},{1,-1},{-1,1},{-1,-1}};
static int n,cnt;//地图大小,记录'y'的数目
public static void main(String[] args) {
FastReader sc=new FastReader();
n=sc.nextInt();
init();
for(int i=0;i<n;i++){
mp[i]=(sc.next()).toCharArray();
for(int j=0;j<n;j++){
if(mp[i][j]=='y'){
record[++cnt][0]=i;
record[cnt][1]=j;
}
}
}
while(cnt>=0){
int i=record[cnt][0];
int j=record[cnt][1];
dfs(i,j);
cnt--;
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(pd[i][j])out.print(mp[i][j]);
else out.print("*");
}
out.println();
out.flush();
}
}
public static void dfs(int x,int y){
for(int i=0;i<8;i++){//搜索方向
boolean flag=true;//判断是否符合'yizhong'
int nx=x,ny=y;
for(int j=1;j<7;j++){//判断字符
nx=nx+dir[i][0];
ny=ny+dir[i][1];
if(nx<0||nx>=n||ny<0||ny>=n||mp[nx][ny]!=ch[j]){
flag=false;
break;
}
}
if(flag){
//注意单词区域可重叠
nx=x;ny=y;
for(int j=0;j<7;j++){
pd[nx][ny]=true;
nx=nx+dir[i][0];
ny=ny+dir[i][1];
}
}
}
}
public static void init(){
//初始化函数
record=new int[n*n][2];
pd=new boolean[n][n];
mp=new char[n][n];
cnt=-1;
}
题目链接:LeetCode994
反思:如同一圈圈向外辐射,腐烂的橘子会把仅周围的橘子也变得腐烂,同一时间内变得腐烂的橘子可以使用队列存储。以下是完整代码。
static int n,m;
static int mp[][];
static int dir[][]={{1,0},{-1,0},{0,1},{0,-1}};//四个方向
public static void main(String[] args) {
FastReader sc = new FastReader();
n=sc.nextInt();//行
m=sc.nextInt();//列
mp=new int[n][m];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
mp[i][j]=sc.nextInt();
}
}
Queue<pair> q=new ArrayDeque<>();
int step=0,cnt=0;//最小分钟数,新鲜橘子个数
pair p;//pair类,属性为腐烂橘子的坐标
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(mp[i][j]==2){
p=new pair(i,j);
q.add(p);
}else if(mp[i][j]==1){
cnt++;
}
}
}
int len=0,x,y,b,c;
while(!q.isEmpty()){
if(cnt==0)break;//没有新鲜的橘子了
len=q.size();
for(int i=0;i<len;i++){
p=q.poll();
x=p.i;y=p.j;
for(int j=0;j<4;j++){
b=x+dir[j][0];
c=y+dir[j][1];
if(b>=0&&b<n&&c>=0&&c<m&&mp[b][c]==1){
cnt--;
p=new pair(b,c);
q.add(p);
mp[b][c]=2;
}
}
}
step++;
}
if(cnt==0)out.println(step);
else out.println(-1);
out.flush();
}
class pair{
int i,j;
public pair(int i,int j){
this.i=i;this.j=j;
}
}