【Java】搜索专题训练

HENAU 冬令营 搜索专题

链接:搜索专题-前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)));
    /*
    核心代码区
     */
}

A - 棋盘问题

题目链接: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);
    }

B - Perket

题目链接:洛谷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);
    }

C - 全排列

题目链接: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;
                }
            }
        }
    }

D - 自然数拆分

题目链接:计蒜客 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;
        }
	}

E - Prime Ring Problem

题目链接: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;
            }
        }
    }

F - Red and Black

题目链接: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]);
        }
    }

G - Knight Moves

题目链接: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
    }

H - Oil Deposits

题目链接: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);//进行搜索
        }
    }

I - Lake Counting

题目链接: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);// 去搜索该点
                }
            }
        }
    }

J - 二叉树先序遍历

题目链接: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);//遍历右子树
    }

K - 迷宫(一)

题目链接:计蒜客 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);
        }
    }

L - 马走日

题目链接: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;
            }
        }
    }

M - 八皇后问题

题目链接:计蒜客

	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];
        }
    }

N - 选数

题目链接:洛谷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;
    }

O - 打开灯泡 Switch the Lamp On

题目链接:洛谷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<iostream>
#include<deque>
#include<cstring>
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;		
} 

P - 单词方阵

题目链接:洛谷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;
    }

Q - 腐烂的橘子

题目链接: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;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值