【kuangbin计划】专题一:简单搜索(6 / 14)

目录

1114. 棋盘问题 - dfs按行枚举

1096. 地牢大师 - 三维bfs求最短路

1100. 抓住那头牛 - 一维bfs求最短路

为什么bfs可以求最短路?

4218. 翻转 - 递推 

4219. 找倍数 - dfs按位枚举 / bfs

1、dfs 

2、bfs

4220. 质数路径 - bfs求最短路


1114. 棋盘问题 - dfs按行枚举

1114. 棋盘问题 - AcWing题库

题目:

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别

要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 k 个棋子的所有可行的摆放方案数目 

思路:

  • 类似与n皇后问题,我们用dfs按行枚举 ,即每行放一个,我们只需要看这一行每一列是否被占即可
  • 从第0行开始枚举,num记录已放好的棋子
  • 在第i行枚举所有列j,如果该位置为棋盘区域且该列未被标记,则标记好
  • 递归进入下一行,num+1
  • 因为要枚举所有情况,因此dfs完要还原现场
  • 要注意:因为棋子个数可能≤行数,因此有的行可以不放
import java.util.*;

class Main
{   
    static int N=10;
    static char[][] g=new char[N][N];
    static int[] col=new int[N]; //按行枚举 因此只需要看每列是否被占用即可
    static int res,n,k;
    
    public static void dfs(int x,int num)
    {
        if(num==k)  //当棋子全部摆好
        {
            res++;
            return;
        }
        if(x>=n) return; //越界
        
        dfs(x+1,num); //可以这一行不放
        
        for(int i=0;i<n;i++)
            if(g[x][i]=='#'&&col[i]==0)
            {
                col[i]=1;
                dfs(x+1,num+1);
                col[i]=0;
            }
    }
    
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        while(true)
        {
            n=sc.nextInt();
            k=sc.nextInt();
            if(n==-1&&k==-1) break;
            
            Arrays.fill(col,0);
            
            for(int i=0;i<n;i++) 
            {
                String s=sc.next();
                for(int j=0;j<n;j++) g[i][j]=s.charAt(j);
            }
            
            res=0;
            dfs(0,0); //从第0行开始dfs,摆好了0个棋子
        
            System.out.println(res);
        }
    }
}

1096. 地牢大师 - 三维bfs求最短路

1096. 地牢大师 - AcWing题库

题目:

你现在被困在一个三维地牢中,需要找到最快脱离的出路!

地牢由若干个单位立方体组成,其中部分不含岩石障碍可以直接通过,部分包含岩石障碍无法通过

向北,向南,向东,向西,向上,向下移动,移动一个单元距离均需要一分钟。

你不能沿对角线移动,迷宫边界都是坚硬的岩石,你不能走出边界范围

可以逃脱输出最短逃生时间,否则输出Trapped!

思路:

采用三维数组跑一个bfs即可

import java.util.*;

class Main
{
    static class Point
    {
        int x,y,z;
        public Point(int x,int y,int z)
        {
            this.x=x;
            this.y=y;
            this.z=z;
        }
    }
    
    static int N=110;
    static char[][][] g=new char[N][N][N]; //长 宽 高
    static int[][][] flag=new int[N][N][N];
    static int[][][] dist=new int[N][N][N];
    static int[] dx={1,-1,0,0,0,0},dy={0,0,-1,1,0,0},dz={0,0,0,0,1,-1};
    static Point st,ed;
    static int l,r,c;
    
    public static int bfs()
    {
        for(int i=0;i<110;i++)
            for(int j=0;j<110;j++)
            {
                Arrays.fill(dist[i][j],-1);
                Arrays.fill(flag[i][j],0);
            }
        Queue<Point> q=new LinkedList<>();
        
        q.offer(st);
        flag[st.x][st.y][st.z]=1;
        dist[st.x][st.y][st.z]=0;
        
        while(!q.isEmpty())
        {
            var t=q.poll();
            
            for(int i=0;i<6;i++)
            {
                int nx=t.x+dx[i],ny=t.y+dy[i],nz=t.z+dz[i];
                if(nx<0||nx>=r||ny<0||ny>=c||nz<0||nz>=l) continue; //越界
                if(g[nx][ny][nz]=='#'||flag[nx][ny][nz]==1) continue;
                dist[nx][ny][nz]=dist[t.x][t.y][t.z]+1;
                flag[nx][ny][nz]=1;
                q.offer(new Point(nx,ny,nz));
            }
        }
        return dist[ed.x][ed.y][ed.z];
    }
    
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        while(true)
        {
            l=sc.nextInt();r=sc.nextInt();c=sc.nextInt();
            if(l==0&&r==0&&c==0) break;
            
            for(int k=0;k<l;k++)
            {
                for(int i=0;i<r;i++)
                {
                    String s=sc.next();
                    for(int j=0;j<c;j++)
                    {
                        g[i][j][k]=s.charAt(j);
                        if(g[i][j][k]=='S') st=new Point(i,j,k);
                        else if(g[i][j][k]=='E') ed=new Point(i,j,k);
                    }
                }
            }
            
            int res=bfs();
            if(res==-1) System.out.println("Trapped!");
            else System.out.printf("Escaped in %d minute(s).\n",res);
 
        }
    }
}

1100. 抓住那头牛 - 一维bfs求最短路

活动 - AcWing

题目:

思路:

用bfs枚举所有方案(-1,+1,*2)

为什么bfs可以求最短路?

因为bfs是一层一层向外拓展,那么每搜一次(即入队一层),路径长度+1,所以最先到终点的那条路径一定是最短的,而且因为走过的点有标记,所以每个点只会遍历一次,则遍历结束后就能知道最短路,所以用BFS可以求任意起点到终点的最短路径

import java.util.*;

class Main
{
    static int N=100110;
    static int[] dist=new int[N];
    static int n,k;
    
    public static int bfs()
    {
        Queue<Integer> q=new LinkedList<>();
        Arrays.fill(dist,-1);
        q.offer(n);
        dist[n]=0;
        
        while(!q.isEmpty())
        {
            var t=q.poll();
            if(t==k) return dist[t];
            int[] dx={-1,1,t};
            
            for(int i=0;i<3;i++)
            {
                int nx=t+dx[i];
                if(nx<0||nx>100000) continue;
                if(dist[nx]!=-1) continue;
                dist[nx]=dist[t]+1;
                q.offer(nx);
            }
        }
        return -1;
    }
    
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();k=sc.nextInt();
        System.out.print(bfs());
    }
}

4218. 翻转 - 递推 

4218. 翻转 - AcWing题库

费解的开关是同类题,详细见下方链接!

【蓝桥杯集训5】递推专题(3 / 3)_Roye_ack的博客-CSDN博客

题目:

思路:

  • 因为每一行的状态都能决定下一行的状态,所以先枚举第0行的所有情况
  • 则000……0~111……1一共有2^m种情况
  • 根据第0行的状态推出第1 ~ n-1行的状态
  • 目标是获得全0矩阵,则枚举到每一行,遇到1时就改变该状态
  • 第i行的状态由第i+1行的状态决定
  • 最后检查最后一行的状态,如果最后一行全为0,说明方案可行,更新最小操作数方案
  • 否则当最后一行有1,则方案不可行
import java.util.*;

class Main
{
    static int N=20;
    static int[][] g=new int[N][N],copy=new int[N][N],ans=new int[N][N];
    static int[][] cur=new int[N][N]; //标记翻转的位置
    static int[] dx={0,0,0,1,-1},dy={0,1,-1,0,0};
    static int m,n,cnt;
    
    public static void turn(int x,int y)
    {
        for(int i=0;i<5;i++)
        {
            int nx=x+dx[i],ny=y+dy[i];
            if(nx<0||nx>=n||ny<0||ny>=m) continue;
            g[nx][ny]^=1;
        }
    }
    
    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++)
            for(int j=0;j<m;j++) copy[i][j]=sc.nextInt();
        
        int res=0x3f3f3f3f;
        for(int op=0;op<(1<<m);op++) //枚举第一行的所有情况000……0~111……1一共2^m种情况
        {
            //取出原矩阵
            for(int i=0;i<n;i++)
                for(int j=0;j<m;j++) g[i][j]=copy[i][j];
            
            //重置cur矩阵
            for(int i=0;i<n;i++) Arrays.fill(cur[i],0);
                
            int cnt=0; //记录翻转次数
                
            for(int i=0;i<m;i++)
                if((op>>i&1)==1)
                {
                    cnt++;
                    turn(0,i);
                    cur[0][i]=1; 
                }
            
            for(int i=0;i<n-1;i++) //递推出第1~n-1行的状态 如果要改变第i行的某个状态,需要改变i+1行
                for(int j=0;j<m;j++)
                    if(g[i][j]==1)
                    {
                        turn(i+1,j);
                        cnt++;
                        cur[i+1][j]=1;
                    }
            
            //看最后一行状态是否符合全0 符合则有方案 不符合则impossible
            boolean f=true;
            for(int i=0;i<m;i++)
                if(g[n-1][i]==1)
                {
                    f=false;
                    break;
                }
            if(f&&res>cnt) //如果符合则更新最小答案
            {
                res=cnt;
                for(int i=0;i<n;i++)
                    for(int j=0;j<m;j++) ans[i][j]=cur[i][j];
            }
        }
        if(res==0x3f3f3f3f) System.out.print("IMPOSSIBLE");
        else 
        {
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<m;j++)
                    System.out.print(ans[i][j]+" ");
                System.out.println();
            }
        }
    }
}

4219. 找倍数 - dfs按位枚举 / bfs

4219. 找倍数 - AcWing题库

题目:

给定一个正整数 n,请你找到一个它的非零倍数 m

要求 m 中只包含数字 0 或 1,并且总位数不超过 100 位

输出任意合法数即可

1、dfs 

import java.util.*;

class Main
{
    static int n;
    static boolean f;
    
    public static void dfs(int u,long sum)
    {
        if(f||u>=19) return; //如果已经找到答案或sum值太大
        if(sum%n==0)
        {
            System.out.println(sum);
            f=true;
            return;
        }
        dfs(u+1,sum*10);
        dfs(u+1,sum*10+1);
    }
    
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        while(true)
        {
            n=sc.nextInt();
            if(n==0) break;
            f=false;
            dfs(0,1);
        }
    }
}

2、bfs

import java.util.*;

class Main
{
    static int n;
    
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        while(true)
        {
            n=sc.nextInt();
            if(n==0) break;
            
            Queue<Pair> q=new LinkedList<>();
            q.offer(new Pair("1",1));
            
            while(!q.isEmpty())
            {
                var t=q.poll();
                if(t.sum==0) {System.out.println(t.s);break;}
                
                q.offer(new Pair(t.s+"1",(t.sum*10+1)%n));
                q.offer(new Pair(t.s+"0",(t.sum*10)%n));
            }
        }
    }
}

class Pair
{
    String s;
    long sum;
    Pair(String s,long sum)
    {
        this.s=s;
        this.sum=sum;
    }
}

4220. 质数路径 - bfs求最短路 - 未ac正在找bug!!!

4220. 质数路径 - AcWing题库

题目:

思路:

将每一位数换成除自身之外的0~9的数,检查是否为质数

如果为质数则记录操作次数,并入队

如果枚举到结果,则返回记录的操作次数

import java.util.*;

class Main
{
    static int N=10010;
    static int[] dist=new int[N];
    static int[] st=new int[N];
    static int[] prime=new int[N];
    
    public static void get_prime()
    {
        prime[0]=1;
        prime[1]=1;
        for(int i=2;i<N;i++)
            if(prime[i]==0)
            {
                for(int j=i+i;j<N;j+=i) prime[j]=1;
            }
    }
    
    public static boolean isprime(int x)
    {
        if(x<2) return false;
        for(int i=2;i<=x/i;i++)
            if(x%i==0) return false;
            return true;
    }
    
    public static int bfs(int a,int b)
    {
        Queue<Integer> q=new LinkedList<>();
        Arrays.fill(st,0);
        Arrays.fill(dist,0);
        q.offer(a);
        st[a]=1;
        
        while(!q.isEmpty())
        {
            var t=q.poll();
            if(t==b) return dist[b];
            int[] d={t/1000,t/100%10,t/10%10,t%10};
            
            
            for(int i=0;i<4;i++)
            {
                int x=d[i];
                for(int j=0;j<10;j++)
                    if(j!=x)
                    {
                        d[i]=j;
                        int sum=d[0]*1000+d[1]*100+d[2]*10+d[3];
                        
                        if(st[sum]==0&&isprime(sum))
                        {
                            st[sum]=1;
                            q.offer(sum);
                            dist[sum]=dist[t]+1;
                        }
                        if(sum==b) return dist[sum];
                    }
                d[i]=x; //还原回去
            }
        }
        return -1;
        
    }
    
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        while(t-->0)
        {
            int a=sc.nextInt(),b=sc.nextInt();
            System.out.println(bfs(a,b));
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值