代码随想录-图论28

kamacoder-98-可达路径

java 复制代码
import java.util.*;
public class Main{
    static List<List<Integer>> result = new ArrayList<>();
    static List<Integer> path = new ArrayList<>();

    public static void dfs(int[][] graph, int x, int n){
        if(x == n){
            result.add(new ArrayList<>(path));
            return;
        }
        for(int i = 1 ; i <= n ; i++){
            if(graph[x][i] == 1){
                path.add(i);
                dfs(graph,i,n);
                path.remove(path.size()-1);
            }
        }
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[][] graph = new int[n+1][n+1];
        for(int i = 0 ; i < m ;i++){
            int s = sc.nextInt();
            int t = sc.nextInt();
            graph[s][t] = 1;
        }
        path.add(1);
        dfs(graph,1,n);
        if(result.isEmpty())
            System.out.println(-1);
        for(List<Integer> pa : result){
            for(int i = 0 ; i < pa.size()-1 ; i++){
                System.out.print(pa.get(i)+" ");
            }
            System.out.println(pa.get(pa.size()-1));
        }
    }
}

kamacoder-99-计数孤岛

深搜

java 复制代码
import java.util.*;
public class Main{
    public static int[][] dir = {{0,1},{1,0},{-1,0},{0,-1}};
    public static void dfs(boolean[][] visited, int x, int y, int[][] grid){
        for(int i = 0 ; i < 4 ; i++){
            int nextX = x + dir[i][0];
            int nextY = y + dir[i][1];
            if(nextX < 0 || nextY < 0 || nextX >= grid.length || nextY >= grid[0].length)
                continue;
            if(!visited[nextX][nextY] && grid[nextX][nextY] == 1){
                visited[nextX][nextY] = true;
                dfs(visited,nextX,nextY,grid);
            }
        }
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int n = sc.nextInt();
        int[][] grid = new int[m][n];
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++){
                grid[i][j] = sc.nextInt();
            }
        }
        boolean[][] visited = new boolean[m][n];
        int ans = 0;
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++){
                if(!visited[i][j] && grid[i][j] == 1){
                    ans++;
                    visited[i][j] = true;
                    dfs(visited,i,j,grid);
                }
            }
        }
        System.out.println(ans);
    }
}

广搜

java 复制代码
import java.util.*;
public class Main{
    public static class pair{
        private int first;
        private int second;
        pair(int first, int second){
            this.first = first;
            this.second = second;
        }
    }

    public static int[][] dir = {{0,1},{1,0},{0,-1},{-1,0}};
    public static void bfs(int[][] grid, boolean[][] visited, int x, int y){
        Queue<pair> queue = new LinkedList<pair>();
        queue.add(new pair(x,y));
        visited[x][y] = true;
        while(!queue.isEmpty()){
            int curX = queue.peek().first;
            int curY = queue.poll().second;
            for(int i = 0 ; i < 4 ; i++){
                int nextX = curX + dir[i][0];
                int nextY = curY + dir[i][1];
                if(nextX < 0 || nextY < 0 || nextX >= grid.length || nextY >= grid[0].length) continue;
                if(!visited[nextX][nextY] && grid[nextX][nextY] == 1){
                    queue.add(new pair(nextX,nextY));
                    visited[nextX][nextY] = true;
                }
            }
        }
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int n = sc.nextInt();
        int[][] grid = new int[m][n];
        boolean[][] visited = new boolean[m][n];
        int ans = 0;
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++){
                grid[i][j] = sc.nextInt();
            }
        }
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++){
                if(!visited[i][j] && grid[i][j] == 1){
                    ans++;
                    bfs(grid,visited,i,j);
                }
            }
        }
        System.out.println(ans);
    }
}

kamacoder-100-最大岛屿面积

java 复制代码
import java.util.*;
public class Main{
    static int[][] dir = {{1,0},{0,1},{-1,0},{0,-1}};
    static int cnt = 0;
    static int res = 0;
    public static void dfs(int[][] graph, boolean[][] visited , int x, int y){   
        cnt++;
        visited[x][y] = true;
        for(int i = 0 ; i < 4 ; i++){
            int nextX = x + dir[i][0];
            int nextY = y + dir[i][1];
            if(nextX < 0 || nextY < 0 || nextX >= graph.length || nextY >= graph[0].length) continue;
            if(!visited[nextX][nextY] && graph[nextX][nextY] == 1){
                
                dfs(graph,visited,nextX,nextY);
            }
        }
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[][] graph = new int[n][m];
        for(int i = 0 ; i < n ; i++){
            for(int j = 0 ; j < m ; j++)
                graph[i][j] = sc.nextInt();
        }
        boolean[][] visited = new boolean[n][m];
        for(int i = 0 ; i < n ; i++){
            for(int j = 0 ; j < m ; j++){
                if(!visited[i][j] && graph[i][j] == 1){
                    cnt = 0;
                    dfs(graph,visited,i,j);
                    res = Math.max(res,cnt);
                }
            }
        }
        System.out.println(res);
    }
}

kamacoder-101-孤岛的总面积

本题要求找到不靠边的陆地面积,那么只要从周边找到陆地然后 通过 dfs或者bfs 将周边靠陆地且相邻的陆地都变成海洋,然后再去重新遍历地图 统计此时还剩下的陆地就可以了。

java 复制代码
import java.util.*;
public class Main{
    static int count = 0;
    static int[][] dir = {{1,0},{0,1},{-1,0},{0,-1}};
    public static void bfs(int[][] grid, int x, int y){
        Queue<int[]> que = new LinkedList<>();
        que.add(new int[]{x,y});
        grid[x][y] = 0;
        count++;
        while(!que.isEmpty()){
            int[] cur = que.poll();
            int curX = cur[0];
            int curY = cur[1];
            for(int i = 0 ; i < 4 ; i++){
                int nextX = curX + dir[i][0];
                int nextY = curY + dir[i][1];
                if(nextX < 0 || nextY < 0 || nextX >= grid.length || nextY >= grid[0].length) continue;
                if(grid[nextX][nextY] == 1){
                    que.add(new int[]{nextX,nextY});
                    count++;
                    grid[nextX][nextY] = 0;
                }
            }
        }
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[][] graph = new int[n][m];
        for(int i = 0 ; i < n ; i++){
            for(int j = 0 ; j < m ; j++)
                graph[i][j] = sc.nextInt();
        }
        //从左侧边,和右侧边向中间遍历
        for(int i = 0 ; i < n ; i++){
            if(graph[i][0] == 1) bfs(graph,i,0);
            if(graph[i][m-1] == 1) bfs(graph,i,m-1);
        }
        //从上边和下边向中间遍历
        for(int j = 0 ; j < m ; j++){
            if(graph[0][j] == 1) bfs(graph,0,j);
            if(graph[n-1][j] == 1) bfs(graph,n-1,j);
        }
        count = 0;
        for(int i = 0 ; i < n ; i++){
            for(int j = 0 ; j < m ; j++){
                if(graph[i][j] == 1) 
                    bfs(graph,i,j);
            }
        }
        System.out.println(count);
    }
}

kamacoder-102-沉没孤岛

思路依然是从地图周边出发,将周边空格相邻的陆地都做上标记,然后在遍历一遍地图,遇到 陆地 且没做过标记的,那么都是地图中间的 陆地 ,全部改成水域就行。

如果再定义一个 visited 二维数组,单独标记周边的陆地,然后遍历地图的时候同时对 地图数组 和 数组visited 进行判断,决定陆地是否变成水域。这样做其实就有点麻烦了,不用额外定义空间了,标记周边的陆地,可以直接改陆地为其他特殊值作为标记。

步骤一:深搜或者广搜将地图周边的 1 (陆地)全部改成 2 (特殊标记)

步骤二:将水域中间 1 (陆地)全部改成 水域(0)

步骤三:将之前标记的 2 改为 1 (陆地)

java 复制代码
import java.util.*;
public class Main{
    static int[][] dir = {{1,0},{0,1},{-1,0},{0,-1}};
    public static void dfs(int[][] grid, int x, int y){
        grid[x][y] = 2;
        for(int i = 0 ; i < 4 ; i++){
            int nextX = x + dir[i][0];
            int nextY = y + dir[i][1];
            if(nextX < 0 || nextY < 0 || nextX >= grid.length || nextY >= grid[0].length) continue;
            if(grid[nextX][nextY] == 0 || grid[nextX][nextY] == 2) continue;
            dfs(grid,nextX,nextY);
        }
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[][] graph = new int[n][m];
        for(int i = 0 ; i < n ; i++){
            for(int j = 0 ; j < m ; j++)
                graph[i][j] = sc.nextInt();
        }
        //从左侧边,和右侧边向中间遍历
        for(int i = 0 ; i < n ; i++){
            if(graph[i][0] == 1) dfs(graph,i,0);
            if(graph[i][m-1] == 1) dfs(graph,i,m-1);
        }
        //从上边和下边向中间遍历
        for(int j = 0 ; j < m ; j++){
            if(graph[0][j] == 1) dfs(graph,0,j);
            if(graph[n-1][j] == 1) dfs(graph,n-1,j);
        }
        
        for(int i = 0 ; i < n ; i++){
            for(int j = 0 ; j < m ; j++){
                if(graph[i][j] == 1) graph[i][j] = 0;
                if(graph[i][j] == 2) graph[i][j] = 1;
            }
        }
        
        for(int i = 0 ; i < n ; i++){
            for(int j = 0 ; j < m ; j++){
                System.out.print(graph[i][j]+" ");
            }
            System.out.println();
        }
    }
}

kamacoder-103-高山流水

可以 反过来想,从第一组边界上的节点 逆流而上,将遍历过的节点都标记上。同样从第二组边界的边上节点 逆流而上,将遍历过的节点也标记上。然后两方都标记过的节点就是既可以流向第一组边界也可以流向第二组边界的节点

java 复制代码
import java.util.*;
public class Main{
    public static void dfs(int[][] height, int x, int y, boolean[][] visited, int preH){
        //遇到边界或者访问过的节点,直接返回
        if(x < 0 || x >= height.length || y < 0 || y >= height[0].length || visited[x][y]) return;
        //不满足水流入条件的直接返回
        if(height[x][y] < preH) return;
        //满足条件,设置为true,表示可以从边界到达此位置
        visited[x][y] = true;

        //向下一层继续搜索
        dfs(height, x+1, y, visited, height[x][y]);
        dfs(height, x-1, y, visited, height[x][y]);
        dfs(height, x, y+1, visited, height[x][y]);
        dfs(height, x, y-1, visited, height[x][y]);
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int n = sc.nextInt();

        int[][] height = new int[m][n];
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++)
                height[i][j] = sc.nextInt();
        }
        boolean[][] pacific = new boolean[m][n];
        boolean[][] atlantic = new boolean[m][n];

        for(int i = 0 ; i < m ; i++){
            dfs(height,i,0,pacific,Integer.MIN_VALUE);
            dfs(height,i,n-1,atlantic,Integer.MIN_VALUE);
        }
        for(int j = 0 ; j < n ; j++){
            dfs(height,0,j,pacific,Integer.MIN_VALUE);
            dfs(height,m-1,j,atlantic,Integer.MIN_VALUE);
        }
        //当两个边界二维数组在某个位置都为true时,符合题目要求
        List<List<Integer>> res = new ArrayList<>();
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++){
                if(pacific[i][j] && atlantic[i][j])
                    res.add(Arrays.asList(i,j));
            }
        }

        for(List<Integer> list : res){
            for(int k = 0 ; k < list.size() ; k++){
                if(k == 0){
                    System.out.print(list.get(k)+" ");
                }else{
                    System.out.print(list.get(k));
                }
            }
            System.out.println();
        }
    }
}

kamacoder-104-建造最大岛屿

只要用一次深搜把每个岛屿的面积记录下来就好。

第一步:一次遍历地图,得出各个岛屿的面积,并做编号记录。可以使用map记录,key为岛屿编号,value为岛屿面积

第二步:再遍历地图,遍历0的方格(因为要将0变成1),并统计该1(由0变成的1)周边岛屿面积,将其相邻面积相加在一起,遍历所有 0 之后,就可以得出 选一个0变成1 之后的最大面积。

java 复制代码
import java.util.*;
public class Main{
    static int count;
    static int mark;
    static int[][] dirs = {{1,0},{0,1},{-1,0},{0,-1}};
    public static void dfs(int[][] grid, int x, int y, boolean[][] visited){
        if(x < 0 || y < 0 || x >= grid.length || y >= grid[0].length) return;
        if(visited[x][y] || grid[x][y] == 0) return;

        visited[x][y] = true;
        count++;
        grid[x][y] = mark;

        dfs(grid,x,y+1,visited);
        dfs(grid,x,y-1,visited);
        dfs(grid,x+1,y,visited);
        dfs(grid,x-1,y,visited);
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int m =sc.nextInt();
        int n = sc.nextInt();

        int[][] grid = new int[m][n];
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++)
                grid[i][j] = sc.nextInt();
        }

        //初始化mark变量,从2开始(区别于0水,1岛屿)
        mark = 2;

        boolean[][] visited = new boolean[m][n];

        //定义一个HashMap,记录某片岛屿的标记号和面积
        HashMap<Integer,Integer> getSize = new HashMap<>();

        //定义一个HashSet,用来判断某一位置水四周是否存在不同标记编号的岛屿
        HashSet<Integer> set = new HashSet<>();

        //定义一个boolean变量,看看DFS之后,是否全是岛屿
        boolean isAllIsland = true;

        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++){
                if(grid[i][j] == 0) isAllIsland = false;
                if(grid[i][j] == 1){
                    count = 0;
                    dfs(grid,i,j,visited);
                    getSize.put(mark,count);
                    mark++;
                }
            }
        }

        int result = 0;
        if(isAllIsland) result = m*n;

        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++){
                if(grid[i][j] == 0){
                    set.clear();
                    int curSize = 1;
                    for(int[] dir : dirs){
                        int curRow = i + dir[0];
                        int curCol = j + dir[1];

                        if(curRow < 0 || curRow >= m || curCol < 0 || curCol >= n) continue;
                        int curMark = grid[curRow][curCol];
                        if(set.contains(curMark) || !getSize.containsKey(curMark)) continue;
                        set.add(curMark);
                        curSize += getSize.get(curMark);
                    }
                    result = Math.max(result,curSize);
                }
            }
        }
        System.out.println(result);
    }
}

kamacoder-105-海岸线计算

不需要dfs或者bfs,只需要记录每个陆地四周是否是边界线或者水域即可

java 复制代码
import java.util.*;
public class Main{
    static int[][] dirs = {{1,0},{0,1},{-1,0},{0,-1}};
    static int count;
    public static void helper(int[][] grid, int x, int y){
        for(int i = 0 ; i < 4 ; i++){
            int nextX = x + dirs[i][0];
            int nextY = y + dirs[i][1];
            if(nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length || grid[nextX][nextY] == 0)
                count++;
        }
    }

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

        int result = 0;
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++){
                if(grid[i][j] == 1){
                    count = 0;
                    helper(grid,i,j);
                    result += count;
                }
            }
        }
        System.out.println(result);
    }
}

kamacoder-110-字符串迁移

所以这道题要解决两个问题:

1、图中的线是如何连在一起的

在搜索的过程中,我们可以枚举,用26个字母替换当前字符串的每一个字符,在看替换后 是否在 strList里出现过,就可以判断 两个字符串 是否是链接的。

2、起点和终点的最短路径长度

首先题目中并没有给出点与点之间的连线,而是要我们自己去连,条件是字符只能差一个。

所以判断点与点之间的关系,需要判断是不是差一个字符,如果差一个字符,那就是有链接

然后就是求起点和终点的最短路径长度,在无权图中,求最短路,用深搜或者广搜就行,没必要用最短路算法。在无权图中,用广搜求最短路最为合适,广搜只要搜到了终点,那么一定是最短的路径 。因为广搜就是以起点中心向四周扩散的搜索。本题如果用深搜,会比较麻烦,要在到达终点的不同路径中选则一条最短路。而广搜只要达到终点,一定是最短路。

另外需要有一个注意点:

  • 本题是一个无向图,需要用标记位,标记着节点是否走过,否则就会死循环!
  • 使用set来检查字符串是否出现在字符串集合里更快一些
复制代码
import java.util.*;
public class Main{
    static Set<String> set = new HashSet<>();
    static Map<String,Integer> map = new HashMap<>();

    public static void main(String[] args){
        Scanner sc= new Scanner(System.in);
        int n = sc.nextInt();
        String beginStr = sc.next();
        String endStr = sc.next();
        for(int i = 0 ; i < n ; i++)
            set.add(sc.next());
        map.put(beginStr,1);
        Queue<String> q = new LinkedList<>();
        q.offer(beginStr);
        while(!q.isEmpty()){
             String word = q.poll();
             int path = map.get(word);
             for(int i = 0 ; i < word.length() ;i++){
                char[] arr = word.toCharArray();
                for(char c = 'a' ; c <= 'z' ; c++){
                    arr[i] = c;
                    String word2 = new String(arr);
                    if(word2.equals(endStr)){
                        System.out.println(path+1);
                        return;
                    }
                    if(set.contains(word2) && !map.containsKey(word2)){
                        map.put(word2,path+1);
                        q.offer(word2);
                    }
                }
             }
        }
        System.out.println(0);
    }
}

kamacoder-105-有向图的完全联通

java 复制代码
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[][] graph = new int[n+1][n+1];
        for(int i = 0 ; i < m ; i++){
            int s = sc.nextInt();
            int t = sc.nextInt();
            graph[s][t] = 1;
        }
        boolean[] visited = new boolean[n+1];
        dfs(graph,1,visited);
        for(int i = 2 ; i <= n ; i++){
            if(!visited[i]){
                System.out.println(-1);
                return;
            }
        }
        System.out.println(1);
    }

    public static void dfs(int[][] graph, int x, boolean[] visited){
        if(visited[x]) return;
        visited[x] = true;
        for(int i = 2 ; i < graph.length ; i++){
            if(graph[x][i] == 1){
                dfs(graph,i,visited);
            }
        }
    }
}
相关推荐
_OP_CHEN1 小时前
【算法基础篇】(四十九)数论之中国剩余定理终极指南:从孙子算经到算法竞赛
算法·蓝桥杯·数论·中国剩余定理·算法竞赛·乘法逆元·acm/icpc
ValhallaCoder1 小时前
Day51-图论
数据结构·python·算法·图论
最低调的奢华2 小时前
支持向量机和xgboost及卡方分箱解释
算法·机器学习·支持向量机
会员果汁2 小时前
leetcode-887. 鸡蛋掉落-C
c语言·算法·leetcode
应用市场2 小时前
人脸识别核心算法深度解析:FaceNet与ArcFace从原理到实战
算法
进击的荆棘3 小时前
优选算法——双指针
数据结构·算法
魂梦翩跹如雨3 小时前
死磕排序算法:手撕快速排序的四种姿势(Hoare、挖坑、前后指针 + 非递归)
java·数据结构·算法
夏鹏今天学习了吗10 小时前
【LeetCode热题100(87/100)】最小路径和
算法·leetcode·职场和发展
哈哈不让取名字10 小时前
基于C++的爬虫框架
开发语言·c++·算法