搜索和图伦1

搜索

在这里插入图片描述

  • 深度优先搜索DFS
    -特点:
    执着人,一路到头,再回头。
    代码特点:回溯 剪枝

  • 数据定义

 数组path-存储路径
 boolean数组-st存储当前的数有没有被用过
 递归-状态改变

题目1:全排列问题
在这里插入图片描述
代码:
数据定义

int path[n]//保存路径
boolean st[N]//保存状态

代码实现

package 大学菜;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class 深度优先搜索遍历 {
    //一条路走到死给定一个整数 n,将数字 1∼n 排成一排,将会有很多种排列方法。
    //现在,请你按照字典序将所有的排列方法输出。
    //3
    //存储路径的
    static int N = 100010;
    static int[] path = new int[N];
    static boolean[] st = new boolean[N];
    static int n;
    public static void dfs(int u){
        //先考虑结束
        if(u>n){
            System.out.println();
            for(int i=1;i<=n;i++){
                System.out.print(path[i]);
            }
        }
        //否则就迭代执行
        for(int i=1;i<=n;i++){
            if(st[i] == false){//渭北访问
                //说明就放它
                path[u] = i;
                st[i] = true;
                dfs(u+1);
                st[i] = false;
            }
        }

    }
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.valueOf(reader.readLine());
        //候选数字就是1-n
        for(int i=1;i<=n;i++){
            st[i] = false;
        }
        dfs(1);//从某一点进行

    }
}

题目2:八皇后问题
解法1.

 剪枝:
剩下的不要,直接剪枝,回溯
col[] //列
dg[] //正斜对角线
udg[]//反对角线技巧:
使用函数进行
判断的时候,进行3个的布尔判断。

图解:
在这里插入图片描述

代码:

package 大学菜;

import java.util.Scanner;

public class n皇后问题4 {
    //第一步数据结构
    static int N =10;
    static int n;
    static char[][] g = new char[N][N];
    static boolean[] col = new boolean[N];
    static boolean[] dg = new boolean[N];
    static boolean[] udg = new boolean[N];

    public static void dfs(int y){
        //判断出口
        if(y==n){
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    System.out.print(g[i][j]);
                }
                System.out.println();
            }
            System.out.println();
        }
        //循环
        for(int x=0;x<n;x++){
            if(col[x] == false&&dg[y+x]==false&&udg[y-x+n]==false){
                g[y][x] = 'Q';
                col[x] = true;
                dg[y+x] = true;
                udg[y-x+n] = true;
                dfs(y+1);
                col[x] = false;
                dg[y+x] = false;
                udg[y-x+n] = false;
                g[y][x] = '.';
            }
        }
    }

    public static void main(String[] args) {
        //接收数据
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                g[i][j] = '.';
            }
        }
        dfs(0);
    }
}

注意

解法2:

```bash
row[]
col[] //行
dg[] //正斜对角线
udg[]//反对角线技巧:
每个格子只有两道选择,一个是放,一个是不放。
进行每个格子的枚举。结束条件:
n个皇后都摆好。
结束条件进行衡量。

暴力解决:
1.先看第一行,枚举法进行
2.在看第二行,枚举

package 大学菜;

import java.util.Scanner;

public class n皇后问题5 {
    static int N =20;//对角线的二倍
    static char[][] g = new char[N][N];
    static boolean[] row = new boolean[N];
    static boolean[] col = new boolean[N];
    static boolean[] dg = new boolean[N];
    static boolean[] udg = new boolean[N];
    static int n;

    public static void dfs(int x,int y,int s){
        if(y==n){
            y=0;x++;
        }
        if(x==n){
            if(s==n){
                for(int i=0;i<n;i++){
                    for(int j=0;j<n;j++){
                        System.out.print(g[i][j]);

                    }
                    System.out.println();
                }
                System.out.println();
            }
            //当这个地方不满足条件的时候,必须要return
            return;///return必须要you

        }
        //出口均不满足
        dfs(x,y+1,s);

        if(row[x] == false && col[y] == false && dg[x+y]==false && udg[x-y+n] == false){
            g[x][y] = 'Q';
            row[x] =col[y] = dg[x+y] = udg[x-y+n]= true;
            dfs(x,y+1,s+1);
            row[x] =col[y] = dg[x+y] = udg[x-y+n]= false;
            g[x][y] ='.';
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                g[i][j] = '.';
            }
        }
        dfs(0,0,0);
    }

}

  • 2.宽度优先搜索
  • 最短路问题:属于DP问题
    一圈圈进行求,先可以求到最短的那个。第一次搜到距离是最短的。
    -层搜,会一次看很多条路,稳重人。扩展性。
    代码特点:
 - 数据定义:
 queue-bfs-
 g[][]//图
 d[][]//juli
路径记录:prep[][]

题目:
走迷宫在这里插入图片描述

在这里插入图片描述
数据结构

成对类
pair<>
queue
g[][]
d[][]
n,m

代码:

package 大学菜;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
class pair<I extends Number, I1 extends Number> {
    int x;
    int y;
    public void pair(int i, int j){
        this.x=i;
        this.y=j;
    }
}
public class 走迷宫 {
    static int N = 110;
    static int[][] g = new int[N][N];
    static int[][] d = new int[N][N];
    static pair<Integer,Integer> p= new pair<Integer,Integer>();
    static Queue<pair> queue = new LinkedList<pair>();
    static int n;
    static int m;

    public static int bfs(){
        //d初始化
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                d[i][j] =-1;
            }
        }
        //方向向量
        pair fir = new pair();
        fir.x=0;
        fir.y=0;
        queue.add(fir);
        d[0][0] = 0;
        int[] dx = {-1,0,1,0};//上右下左
        int[] dy = {0,1,0,-1};
        //开始点:
        while (!queue.isEmpty()){
            p = queue.poll();//出队列
            //看看四个方向
            for(int i=0;i<4;i++){
                int x = p.x+dx[i];//x方向
                int y = p.y+dy[i];//y方向
                if(x>=0 && x<n && y>=0 && y<m && g[x][y]==0 && d[x][y]==-1 ){
                    d[x][y] = d[p.x][p.y]+1;
                    ///入队
                    pair a = new pair();
                    a.x=x;
                    a.y=y;
                    queue.offer(a);
                }
            }
        }
        return d[n-1][m-1];
    }

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String[] str = reader.readLine().split(" ");
        n = Integer.valueOf(str[0]);
        m = Integer.valueOf(str[1]);

        for(int i=0;i<n;i++){
            String[] s= reader.readLine().split(" ");
            for(int j=0;j<m;j++){
                g[i][j] = Integer.valueOf(s[j]);
                //System.out.println(g[i][j]);
            }
        }
        System.out.println(bfs());
    }
}

对比

对比:DFS VS BFS
方法:递归。 接替入站
数据结构:stack  queue
题目:深搜  最短路径
时间:O(h) O(2^h)

空间性优势“DFS
最短路径优势:BFS
层搜:具有最短路径的性质。第一次搜到的距离一定是最短距离。

树和图的存储和遍历

树是一个特殊的图。无环连通图。
无向图是一种特殊的有向图。

- 有向图的存储-

存储方式
1.邻接矩阵
2.邻接表

在这里插入图片描述

代码:

数据结构:
h[N]
e[M]
next[M]
index[]
//初始化,头指向-1
  • 树和图的遍历:
  •  深度优先遍历
    
  •  题目1:树的重心-找最深最多的点
    

在这里插入图片描述
代码:

package 大学菜;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/*给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。
请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。*/
public class 树的中心 {
    //需要找出每个连通块中的点的总共数量中的最小值
    //第一行包含整数 n,表示树的结点数。
    //树是特殊的图,所以可以用图存储-
    //接下来 n−1 行,每行包含两个整数 a 和 b,表示点 a 和点 b 之间存在一条边。
    //邻接表存储
    static int N=100010;
    static int[] h=new int[N];
    static int[] e=new int[N*2];
    static int[] next = new int[N *2];
    static int index;
    static int n;
    static int ans =N;

    static boolean st[] = new boolean[N];

    public static void add(int a,int b){//建一条a-b的边
        e[index] = b;
        next[index] = h[a];
        h[a] = index;
        index++;
    }

    //最小的最大值
    public static int dfs(int u){

        st[u] = true;//访问过这个点就true;
        int size =0;//当前这个的res
        int sum = 1;
        //出口
        for(int i=h[u]; i !=-1;i=next[i]){
            int j = e[i];
            if(st[j]) continue;
            int s = dfs(j);//到这里
            size = Math.max(size,s);//返回到
            sum = sum+s;//

        }
        //上半部分
        size = Math.max(size,n-sum);
        ans = Math.min(size,ans);//最大的最小。
        return sum;
    }



    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.valueOf(reader.readLine());
        //建图
        //初始化时,都指向-1
        for (int i = 0; i < h.length; i++) {
            h[i] = -1;
        }
        for (int i = 0; i < n - 1; i++) {
            String[] str = reader.readLine().split(" ");
            int a = Integer.valueOf(str[0]);
            int b = Integer.valueOf(str[1]);
            //邻接表加边
            add(a, b);
            add(b, a);
        }
        //搜索点u-连通
        //记录每个点成为重心后的最大连通点个数,在这些最大的连通点个数中,找出最小的。
        dfs(1);
        System.out.println(ans);
    }
}

注意:

1.N初始化
2.最大值的最小值初始化。
3.头节点的初始化。
数据结构:
每个点只遍历一次
在邻接表的基础上
h[N]
e[M]
next[M] 
index[]
st[N]//状态
boolean[]

题目1:
例如说这个节点4:
h[4]-3,6,1
实际上这三个点都属于4的邻接表里next点,所以都回去遍历。
但是最后一次循环返回的9.
在这里插入图片描述

广度优先遍历

- 数据结构
- h[N]
e[M]
next[M] 
index[]
- d[N]
- Q[N]
- /*终点
* 1。结构定义-queue
* 2。距离初始化
* 3。头节点初始化
* 4。图存储-领邻接表
* 要素:h[],next[],index,e[]*/

在这里插入图片描述输出层次
在这里插入图片描述
代码:

package 大学菜;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;

/*终点
* 1。结构定义-queue
* 2。距离初始化
* 3。头节点初始化
* 4。图存储-领邻接表
* 要素:h[],next[],index,e[]*/
public class 层次最短距离2 {
    static int N = 100010;
    static int[] h = new int[N];
    static int[] next = new int[N];
    static int[] e = new int[N];
    static int index;

    static Queue<Integer> queue = new LinkedList<>();
    static int[] d = new int[N];
    static int n;
    public static void add(int a,int b){
        e[index] =b;
        next[index] = h[a];
        h[a] = index;
        index++;
    }
    public static int bfs(){
        //初始化
        for(int i= 0;i<d.length;i++){
            d[i] = -1;
        }
        d[1]=0;
        queue.add(1);

        while (!queue.isEmpty()){
            int p = queue.poll();
            for(int i=h[p];i!=-1;i=next[i]){
                int j = e[i];
                if(d[j] == -1){
                    d[j] = d[p]+1;
                    queue.add(j);
                }
            }
        }
        return d[n];
    }

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String[] s = reader.readLine().split(" ");
        n = Integer.valueOf(s[0]);
        int m = Integer.valueOf(s[1]);
        for(int i=0;i<h.length;i++){
            h[i] = -1;
        }
        for(int i=0;i<m;i++){
            String[] s2 = reader.readLine().split(" ");
            int a = Integer.valueOf(s2[0]);
            int b = Integer.valueOf(s2[1]);
            add(a,b);
        }
        System.out.println(bfs());
    }
}

  • 宽搜应用:

拓扑序列:

所有的边都是从前指向后的。
有向无环图。至少存在一个入度为0的点。
用度数进行衡量 
开始:队列放入入度为0的点p
每次都进行判断,
删除p,它的邻接点如果也有入度为0的点的话,也继续入队列
使用数组进行记录被删去的点。
如果当前点有点是也是入度为0,就进队列。
q[N]
d[N]

代码:

package 大学菜;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;

/*终点
 * 1。结构定义-queue
 * 2。距离初始化
 * 3。头节点初始化
 * 4。图存储-领邻接表
 * 要素:h[],next[],index,e[]*/
public class 拓扑序列 {
    static int N = 100010;
    static int[] h = new int[N];
    static int[] next = new int[N];
    static int[] e = new int[N];
    static int index;

    static Queue<Integer> queue = new LinkedList<>();
    static int[] d = new int[N];//入度
    static int n,cnt=1;
    //记录数组:
    static int[] top = new int[N];
    public static void add(int a,int b){
        e[index] =b;
        next[index] = h[a];
        h[a] = index;
        index++;
    }
    public static boolean topbfs(){
        //初始化-- cuoqu
        for(int i=1;i<=n;i++){
            if(d[i] == 0){
                queue.add(i);
            }
        }
        //
        while (!queue.isEmpty()){
            int p = queue.poll();
            top[cnt] = p;
            cnt++;
            for(int i=h[p];i!=-1;i=next[i]){
                int j = e[i];
                d[j]--;
                if(d[j] == 0){
                    queue.add(j);
                }
            }
        }
        return cnt>=n;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String[] s = reader.readLine().split(" ");
        n = Integer.valueOf(s[0]);
        int m = Integer.valueOf(s[1]);
        for(int i=0;i<h.length;i++){
            h[i] = -1;
        }
        for(int i=0;i<m;i++){
            String[] s2 = reader.readLine().split(" ");
            int a = Integer.valueOf(s2[0]);
            int b = Integer.valueOf(s2[1]);
            add(a,b);
            d[b]++;
        }
        if(topbfs()){
            for(int i=1;i<=n;i++){
                System.out.println(top[i]+" ");
            }
        }else System.out.print("-1");
    }
}
//3 3
//1 2
//2 3
//1 3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值