搜索练习1

69 阅读5分钟

例题1

image.png 来自洛谷p0136

看到样例的范围很小我们就也可以暴力的去搜索(dfs) 这题和全排列很像,但它要的是数字的组合总和

首先我们可以先实现判断是否是素数的方法

static boolean isprnum(int s){
    if(s==1)return false;
    for(int i=2;i*i<=s;i++){
        if(s%i==0)
            return false;
    }
    return true;
}

然后实现dfs的主体

DFS

主要就是递归实现,先定义一个回溯条件,然后在去实现递归的过程

显然这里的结束条件是组合了k个数时候判断是否是素数最后退出这一层递归回到上一层,这里不能像全排列那样判断是否使用过这个数(找到后面数,不能回头再找前面的数,因为那样的组合已经存在过了),总体的思想就是以索引1为第一个往后找后三个,找完了就以索引2往后找,以此类推相当于暴力枚举吧,组合的总和也需要回溯所以DFS的参数应该有(个数,和,索引起点)三个参数那么完整的代码就好了

public class problem3 {
    static int n;
    static int []a=new int[22];
    static boolean[]road=new boolean[22];
    static int k;
    static long ans=0;


    static boolean isprnum(int s){
        if(s==1)return false;
        for(int i=2;i*i<=s;i++){
            if(s%i==0)
                return false;
        }
        return true;
    }
    static void dfs(int x,int sum,int index){
        if(x==k){
            if(isprnum(sum)) ans++;
            return;
            }
        for(int i=index;i<=n;i++){
                dfs(x+1,sum+a[i],i+1);
        }
    }

    static void solve(){
        n=sc.nextInt();
        k=sc.nextInt();
        for (int i=1;i<=n;i++){
            a[i]=sc.nextInt();
        }
        dfs(0,0,1);
        out.println(ans);
    }
    public static void main(String[] args) {
        int  T=1;
        while(T-->0){
            solve();
        }
        out.flush();
        out.close();
    }



    static Kattio sc = new Kattio();
    static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

    static class Kattio {
        static BufferedReader r;
        static StringTokenizer st;

        public Kattio() {
            r = new BufferedReader(new InputStreamReader(System.in));
        }

        public String next() {
            try {
                while (st == null || !st.hasMoreTokens()) {
                    st = new StringTokenizer(r.readLine());
                }
                return st.nextToken();
            } catch (Exception e) {
                return null;
            }
        }

        public int nextInt() {
            char[] str = next().toCharArray();
            int i = 0;
            boolean neg = false;
            if (str[0] == '-') {
                i = 1;
                neg = true;
            }
            int ans = 0;
            for (; i < str.length; i++) ans = ans * 10 + (str[i] - '0');
            return neg ? -ans : ans;
        }

        public long nextLong() {
            char[] str = next().toCharArray();
            int i = 0;
            boolean neg = false;
            if (str[0] == '-') {
                i = 1;
                neg = true;
            }
            long ans = 0;
            for (; i < str.length; i++) ans = ans * 10 + (str[i] - '0');
            return neg ? -ans : ans;
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }
    }
}

这里的输入输出我使用的是自定义的输入流和输出流可以减少大量的时间,这个模版不需要学会,直接引用就行了

例题2

image.png

题目大意:

根据预报,一共有 𝑀M 颗流星 (1≤𝑀≤50,000) 会坠落在农场上,其中第 𝑖i 颗流星会在时刻 𝑇𝑖(0≤𝑇𝑖≤1000 )砸在坐标为 (𝑋𝑖,𝑌𝑖)(0≤𝑋𝑖≤300 0≤Yi​≤300) 的格子里。流星的力量会将它所在的格子,以及周围 44 个相邻的格子都化为焦土,当然贝茜也无法再在这些格子上行走。

贝茜在时刻 0 开始行动,她只能在会在横纵坐标 𝑋,𝑌≥0X,Y≥0 的区域中,平行于坐标轴行动,每 11 个时刻中,她能移动到相邻的(一般是 4个)格子中的任意一个,当然目标格子要没有被烧焦才行。如果一个格子在时刻 𝑡t 被流星撞击或烧焦,那么贝茜只能在 𝑡t 之前的时刻在这个格子里出现。 贝茜一开始在 (0,0)。

请你计算一下,贝茜最少需要多少时间才能到达一个安全的格子。如果不可能到达输出 −1。

一般求最少时间可考虑bfs算法

基本步骤就是开始考虑是否创建节点类用于保存某点的数据

这里显然我们要保存到达(x,y)节点时的时间

static class node {
    int x;
    int y;
    int step;
    public node(int x, int y, int step) {
        this.x = x;
        this.y = y;
        this.step = step;
    }
}

同时每一个节点什么时候不能走用二维数组存,以最先烧焦时间为准

//方向
static int[] dx = {1, 0, -1, 0};
static int[] dy = {0, 1, 0, -1};
//节点什么时候不能走,一直能走设为无穷大
static int [][]ends=new int [305][305];
static boolean[][]road=new boolean[305][305];

static void solve() {
    for (int i = 0; i < ends.length; i++) {
        Arrays.fill(ends[i],1005);
    }
    int T =sc.nextInt();
    while (T-- > 0) {
        int x=sc.nextInt();
        int y=sc.nextInt();
        int t=sc.nextInt();
        ends[x][y]= Math.min(ends[x][y],t);
        for (int i = 0; i < 4; i++) {
            int a=x+dx[i];
            int b=y+dy[i];
            if(a>=0&&b>=0)
            ends[a][b]= Math.min(ends[a][b],t);
        }
    }
    int step = bfs();

    System.out.println(step);
}

接下来就是bfs的主体

BFS

首先创建一个队列存取节点,将起始节点放入队列 当然如果起始节点最后还是安全的话,那么直接返回0就行了

然后就要对地图进行层序遍历,取出队列的尾巴,然后又将该节点周围的节点存进队列当然时间+1,如果已经走过就不存了.直到到达安全区

static int  bfs(){
    Queue<node>queue=new LinkedList<>();
    queue.offer(new node(0,0,0));
    if(ends[0][0]>1000) return 0;
    road[0][0]=true;
    while (!queue.isEmpty()){
        node node = queue.poll();
        for (int i = 0; i < 4; i++) {
            int x=node.x+dx[i];
            int y=node.y+dy[i];
            if(x>=0&&y>=0&&node.step+1<ends[x][y]&&!road[x][y]){
                if(ends[x][y]>1000)
                    return node.step+1;
                road[x][y]=true;
                queue.offer(new node(x,y,node.step+1));
            }
        }
    }
    return -1;
}

逻辑是很简单的

Ac代码如下:

import java.io.*;
import java.util.*;

public class problem {
    static int[] dx = {1, 0, -1, 0};
    static int[] dy = {0, 1, 0, -1};
    static int [][]ends=new int [305][305];
    static boolean[][]road=new boolean[305][305];
    static class node {
        int x;
        int y;
        int step;
        public node(int x, int y, int step) {
            this.x = x;
            this.y = y;
            this.step = step;
        }
    }
    static int  bfs(){
        Queue<node>queue=new LinkedList<>();
        queue.offer(new node(0,0,0));
        if(ends[0][0]>1000) return 0;
        road[0][0]=true;
        while (!queue.isEmpty()){
            node node = queue.poll();
            for (int i = 0; i < 4; i++) {
                int x=node.x+dx[i];
                int y=node.y+dy[i];
                if(x>=0&&y>=0&&node.step+1<ends[x][y]&&!road[x][y]){
                    if(ends[x][y]>1000)
                        return node.step+1;
                    road[x][y]=true;
                    queue.offer(new node(x,y,node.step+1));
                }
            }
        }
        return -1;
    }

    static void solve() {
        for (int i = 0; i < ends.length; i++) {
            Arrays.fill(ends[i],1005);
        }
        int T =sc.nextInt();
        while (T-- > 0) {
            int x=sc.nextInt();
            int y=sc.nextInt();
            int t=sc.nextInt();
            ends[x][y]= Math.min(ends[x][y],t);
            for (int i = 0; i < 4; i++) {
                int a=x+dx[i];
                int b=y+dy[i];
                if(a>=0&&b>=0)
                ends[a][b]= Math.min(ends[a][b],t);
            }
        }
        int step = bfs();

        System.out.println(step);
    }

    public static void main(String[] args) {
        int T = 1;
        while (T-- > 0) {
            solve();
        }
        out.flush();
        out.close();
    }


    static Kattio sc = new Kattio();
    static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

    static class Kattio {
        static BufferedReader r;
        static StringTokenizer st;

        public Kattio() {
            r = new BufferedReader(new InputStreamReader(System.in));
        }

        public String next() {
            try {
                while (st == null || !st.hasMoreTokens()) {
                    st = new StringTokenizer(r.readLine());
                }
                return st.nextToken();
            } catch (Exception e) {
                return null;
            }
        }

        public int nextInt() {
            char[] str = next().toCharArray();
            int i = 0;
            boolean neg = false;
            if (str[0] == '-') {
                i = 1;
                neg = true;
            }
            int ans = 0;
            for (; i < str.length; i++) ans = ans * 10 + (str[i] - '0');
            return neg ? -ans : ans;
        }

        public long nextLong() {
            char[] str = next().toCharArray();
            int i = 0;
            boolean neg = false;
            if (str[0] == '-') {
                i = 1;
                neg = true;
            }
            long ans = 0;
            for (; i < str.length; i++) ans = ans * 10 + (str[i] - '0');
            return neg ? -ans : ans;
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }
    }


}