蓝桥杯之BFS和图论

1.BFS求最短路

链接:3.迷宫 - 蓝桥云课 (lanqiao.cn)

这个题很明显滴BFS,但需要考虑的一点就是它与输出最短距离还是有点区别的,需要输出字典序最小的路径,字典序最小我们可以通过方向向量来控制,路径我们可以在定义一个节点类的时候加上去,这样每走到一个点就会对应相应的路径!!!

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

//第十届蓝桥杯迷宫;BFS
public class Maze {
    static char[][] g = new char[30][50];
    static int[] dx = {1,0,0,-1};//D L R U
    static int[] dy = {0,-1,1,0};
    static String[] d = { "D", "L", "R", "U" };
    static Queue<Node> q = new LinkedList<>();
    static String ans="";
    static boolean[][]st=new boolean[30][50];

    public static void main(String[] args) {

        String string = "01010101001011001001010110010110100100001000101010"
                +"00001000100000101010010000100000001001100110100101"
                +"01111011010010001000001101001011100011000000010000"
                +"01000000001010100011010000101000001010101011001011"
                +"00011111000000101000010010100010100000101100000000"
                +"11001000110101000010101100011010011010101011110111"
                +"00011011010101001001001010000001000101001110000000"
                +"10100000101000100110101010111110011000010000111010"
                +"00111000001010100001100010000001000101001100001001"
                +"11000110100001110010001001010101010101010001101000"
                +"00010000100100000101001010101110100010101010000101"
                +"11100100101001001000010000010101010100100100010100"
                +"00000010000000101011001111010001100000101010100011"
                +"10101010011100001000011000010110011110110100001000"
                +"10101010100001101010100101000010100000111011101001"
                +"10000000101100010000101100101101001011100000000100"    //D -> L -> R -> U
                +"10101001000000010100100001000100000100011110101001"
                +"00101001010101101001010100011010101101110000110101"
                +"11001010000100001100000010100101000001000111000010"
                +"00001000110000110101101000000100101001001000011101"
                +"10100101000101000000001110110010110101101010100001"
                +"00101000010000110101010000100010001001000100010101"
                +"10100001000110010001000010101001010101011111010010"
                +"00000100101000000110010100101001000001000000000010"
                +"11010000001001110111001001000011101001011011101000"
                +"00000110100010001000100000001000011101000000110011"
                +"10101000101000100010001111100010101001010000001000"
                +"10000010100101001010110000000100101010001011101000"
                +"00111100001000010000000110111000000001000000001011"
                +"10000001100111010111010001000110111010101101111000";

        for (int i = 0 ; i < 30 ; i++) {
            for(int j = 0 ; j < 50 ; j++) {
                g[i][j] = string.charAt(i*50+j); //
            }
        }

        bfs();




    }
    public static void bfs(){
        q.offer(new Node(0,0,""));
        st[0][0]=true;


        while(!q.isEmpty()){
            Node t = q.poll();

            for (int i = 0; i <4 ; i++) {
                int x=t.x+dx[i];
                int y=t.y+dy[i];
                String rode = t.Rode;


                if(t.x==29&&t.y==49){
                    System.out.print(t.Rode);
                    break;
                }

                if(x>=0&&x<30&&y>=0&&y<50&&!st[x][y]&&g[x][y]=='0'){
                    st[x][y]=true;
                    q.offer(new Node(x,y,rode+d[i]));

                }
            }

        }




    }


    public static class Node{
        int x;
        int y;
        String Rode;

        public Node(int x, int y, String rode) {
            this.x = x;
            this.y = y;
            Rode = rode;
        }
    }

}



2.BFS求最少操作步数

链接:15.九宫重排 - 蓝桥云课 (lanqiao.cn)

我们都知道数字华容道吧,当然我是通过最强大脑这个节目了解的,题目的意思就是我们至少需要多少步能完成它!!!

BFS就是扩展与它相邻的点,很明显,我们可以将 .  与它周围的四个点进行交换,与最终成功的答案比较。  交换一次就得到了新的字符串,我们可以用HashMap<String,Intenger>来统计,String记录路径,Intenger记录的是经过交换得到该字符串的最小操作步数。



import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class 九宫重排 {
    static HashMap<String,Integer>map=new HashMap<>();
    static Queue<String>q=new LinkedList<>();
    static int[]dx={1,0,0,-1};
    static int[]dy={0,-1,1,0};

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        String start = sc.next();
        String end=sc.next();

        System.out.println(bfs(start,end));


    }


    public static int bfs(String start,String end){
        q.offer(start);
        map.put(start,0);

        while (!q.isEmpty()){
            String t = q.poll();

            if(t.equals(end)){
                return map.get(t);
            }



            int index = t.indexOf('.');
            int tx=index/3;
            int ty=index%3;
            int step=map.get(t);


            for (int i = 0; i < 4; i++) {
                int x=tx+dx[i];
                int y=ty+dy[i];
                if(x>=0&&x<3&&y>=0&&y<3){
                    char[] chars = t.toCharArray();
                    swap(chars,x*3+y,index);

                    String s=new String(chars);
                    if(!map.containsKey(s)){
                        map.put(s,step+1);
                        q.offer(s);
                    }
                }
            }



        }
        return -1;

    }
    public static void swap(char[]Chars ,int i,int j){
        char temp=Chars[i];
        Chars[i]=Chars[j];
        Chars[j]=temp;
    }


}

3.Dijkstra算法

单源最短路用它用它用它!!!!!

import java.util.Arrays;
import java.util.Scanner;

public class Dijkstra {
    static int N = 510,n,m, max = 0x3f3f3f3f;
    static int[][] g = new int[N][N];//存每个点之间的距离
    static int[] dist = new int[N];//存每个点到起点之间的距离
    static boolean[] st = new boolean[N];//存已经确定了最短距离的点
    public static int dijkstra(){
        Arrays.fill(dist,max);//将dist数组一开始赋值成较大的数
        dist[1] = 0; //首先第一个点是零

        //从0开始,遍历n次,一次可以确定一个最小值
        for(int i = 0 ; i < n ; i ++ ){
            int t = -1; //t这个变量,准备来说就是转折用的
            for(int j = 1 ; j <= n ; j ++ ){
                /***
                 * 因为数字是大于1的,所以从1开始遍历寻找每个数
                 * 如果s集合中没有这个数
                 * 并且t == -1,表示刚开始 或者 后面的数比我心找的数距离起点的距离短
                 * 然后将j 的值赋值给 t
                 ***/
                if(!st[j] && (t == -1 || dist[j] < dist[t])){
                    t = j;
                }
            }

            st[t] = true;//表示这个数是已经找到了确定了最短距离的点

            //用已经确认的最短距离的点来更新后面的点
            //就是用1到t的距离加上t到j的距离来更新从1到j的长度
            for(int j = 1 ; j <= n ; j ++ ){
                //
                dist[j] = Math.min(dist[j],dist[t] + g[t][j]);
            }
        }
        //如果最后n的长度没有改变,输出-1,没有找到;否则输出最短路n
        if(dist[n] == max) return -1;
        else return dist[n];

    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        //将他们每个点一开始赋值成一个较大的值
        for(int i = 1 ; i <= n ; i ++ ){
            Arrays.fill(g[i],max);
        }
        while(m -- > 0){
            int a = scan.nextInt();
            int b = scan.nextInt();
            int c = scan.nextInt();
            g[a][b] = Math.min(g[a][b],c);//这个因为可能存在重边,所以泽出最短的
        }
        int res = dijkstra();
        System.out.println(res);
    }





}

4.Floyd算法

多源最短路用它用它用它!!!!


import java.util.Scanner;

public class Floyd {
    static int N = 210,n,m,k,INF = 0x3f3f3f3f;
    static int[][] g = new int[N][N];

    /***floyd算法只需要三重循环就可以解决问题,hh《很简单》
     * g[i,j,k] = min(g[i,j,k-1],g[i,k,k-1]+g[k,j,k-1]);
     * 原状态是:f[i, j, k]表示从i走到j的路径上除了i, j以外不包含点k的所有路径的最短距离。
     * 那么f[i, j, k] = min(f[i, j, k - 1), f[i, k, k - 1] + f[k, j, k - 1]。
     * 因此在计算第k层的f[i, j]的时候必须先将第k - 1层的所有状态计算出来,所以需要把k放在最外层。
     *
     * 这里其实就是将所有k的可能性已经·存好,等待你输入就OK了
     ***/
    public static void floyd(){
        for(int k = 1 ; k <= n ; k ++ ){
            for(int i = 1 ; i <= n ; i ++ ){
                for(int j = 1 ; j <= n ; j ++ ){
                    g[i][j] = Math.min(g[i][j],g[i][k] + g[k][j]);
                }
            }
        }
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        k = scan.nextInt();
        for(int i = 1 ; i <= n ; i ++ ){
            for(int j = 1 ; j <= n ; j ++ ){
                if(i == j) g[i][j] = 0; //可能存在询问自身到自身的距离,所以需要存0
                else g[i][j] = INF; //然后其他都可以存成INF最大值
            }
        }
        while(m -- > 0 ){
            int a = scan.nextInt();
            int b = scan.nextInt();
            int c = scan.nextInt();
            g[a][b] = Math.min(g[a][b],c); //这里可能存在重边,取最小的边
        }

        floyd();

        while(k -- > 0){
            int x = scan.nextInt();
            int y = scan.nextInt();
            int t  = g[x][y];
            //这里可能最后到不了目标点,但是可能路径上面存在负权边,然后将目标点更新了,所以不是到底== INF
            if(t > INF / 2) System.out.println("impossible");
            else System.out.println(t);

        }
    }
}


5.图的存储

图的存储方式有邻接矩阵和邻接表两种。

邻接矩阵很简单,下面重要说一下邻接表的模拟实现。

  static int[]h=new int[N],e=new int[N],ne=new int[N];
  static int idx;


   public static void add(int a,int b,int c){
       e[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx++;
   }

6.拓扑排序

链接:848. 有向图的拓扑序列 - AcWing题库


import java.util.*;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    public static int N = 100010, idx = 0, n, m;
    public static int[] h = new int[N], e = new int[N], ne = new int[N];
    public static int[] d = new int[N];
    static ArrayList<Integer>list=new ArrayList<>();
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        Arrays.fill(h, -1);
        for (int i = 0; i < m; i++){
            int a = sc.nextInt(), b = sc.nextInt();
            add(a, b);
        }
        top_sort();

    }

    public static void add(int a, int b){
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
        d[b]++;
    }

    public static void top_sort(){
        Queue<Integer> q = new LinkedList<>();
        for (int i = 1; i <= n; i++) {
            if (d[i] == 0) q.add(i);
        }
        while (!q.isEmpty()) {
            int t = q.poll();
            list.add(t);
            for (int i = h[t]; i != -1; i = ne[i]) {
                int j = e[i];
                d[j]--;
                if (d[j] == 0) q.offer(j);
            }
        }
        if(list.size()==n){
            for (int i = 0; i < list.size(); i++) {
                System.out.print(list.get(i)+" ");
            }
        }else{
            System.out.println(-1);
        }

    }
}

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值