代码随想录算法训练营四十六天|图论part04

岛屿问题(八)岛屿的周长

题目描述

给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。

你可以假设矩阵外均被水包围。在矩阵中恰好拥有一个岛屿,假设组成岛屿的陆地边长都为 1,请计算岛屿的周长。岛屿内部没有水域。

输入描述

第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。

输出描述

输出一个整数,表示岛屿的周长。

输入示例

5 5

0 0 0 0 0

0 1 0 1 0

0 1 1 1 0

0 1 1 1 0

0 0 0 0 0

输出示例

14

提示信息

岛屿的周长为 14。

数据范围:

1 <= M, N <= 50。

思路:

首先为了防止有的岛屿外没有水包围,我们给原有的矩阵外包一圈水。

之后遍历矩阵(不需要遍历外面那一圈水),如果当前坐标是陆地,那么遍历它上下左右看是否有水,如果有的话,那一条边就是周长的一部分,就需要算在周长里。

代码如下:

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

public class Main{
    private static int ans=0;
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        int n=in.nextInt();
        int m=in.nextInt();
        int[][] graph=new int[n+2][m+2];
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                graph[i][j]=in.nextInt();
            }
        }
        boolean[][] visited=new boolean[n+2][m+2];
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(graph[i][j]==1&&visited[i][j]==false){
                    visited[i][j]=true;
                    dfs(graph,visited,i,j);
                }
            }
        }
        System.out.println(ans);
    }
    private static int[][] dir={{0,1},{1,0},{-1,0},{0,-1}};
    public static void dfs(int[][] graph,boolean[][] visited,int x,int y){
        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(graph[nextx][nexty]==0)ans++;
            if(graph[nextx][nexty]==1&&visited[nextx][nexty]==false){
                visited[nextx][nexty]=true;
                dfs(graph,visited,nextx,nexty);
            }
        }
    }
}

字符串接龙

题目描述

字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列:

序列中第一个字符串是 beginStr。

序列中最后一个字符串是 endStr。

每次转换只能改变一个位置的字符(例如 ftr 可以转化 fty ,但 ftr 不能转化 frx)。

转换过程中的中间字符串必须是字典 strList 中的字符串。

beginStr 和 endStr 不在 字典 strList 中

字符串中只有小写的26个字母

给你两个字符串 beginStr 和 endStr 和一个字典 strList,找到从 beginStr 到 endStr 的最短转换序列中的字符串数目。如果不存在这样的转换序列,返回 0。

输入描述

第一行包含一个整数 N,表示字典 strList 中的字符串数量。 第二行包含两个字符串,用空格隔开,分别代表 beginStr 和 endStr。 后续 N 行,每行一个字符串,代表 strList 中的字符串。

输出描述

输出一个整数,代表从 beginStr 转换到 endStr 需要的最短转换序列中的字符串数量。如果不存在这样的转换序列,则输出 0。

输入示例:

6

abc def

efc

dbc

ebc

dec

dfc

yhn

输出示例

4

提示信息

从 startStr 到 endStr,在 strList 中最短的路径为 abc -> dbc -> dec -> def,所以输出结果为 4,如图:

数据范围:

2 <= N <= 500

思路:

首先我们要解决两个问题:

1.图中的边是怎么来的?我们用26个英文字母替换当前字符串的每一个字符,看替换后是否在strList中出现过,如果出现过,那么这里就有一条边。

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

直接使用广搜法,只要搜到了终点(也就是endString),那么就一定是最短路径。这里如果用深搜法会比较麻烦,因为需要再到达终点的不同路径中选一条最短路径。

需要注意的是我们需要标记节点是否走过,这里使用set集合来检查会更快一点。

代码如下:

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

public class Main{
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        int n=in.nextInt();
        String begin=in.next();
        String end=in.next();
        List<String> list=new ArrayList<>();
        list.add(begin);
        list.add(end);
        for(int i=0;i<n;i++){
            list.add(in.next());
        }
        int ans=bfs(begin,end,list);
        System.out.println(ans);
    }
    public static int bfs(String begin,String end,List<String> list){
        int len=1;
        Set<String> set=new HashSet<>();//相当于visited
        Queue<String> q=new LinkedList<>();
        q.offer(begin);
        q.offer(null);
        while(!q.isEmpty()){
            String tmp=q.poll();
            if(tmp==null){
                if(!q.isEmpty()){
                    len++;
                    q.offer(null);
                }
                continue;
            }
            set.add(tmp);
            char[] array=tmp.toCharArray();
            for(int i=0;i<array.length;i++){
                char old=array[i];
                for(char ch='a';ch<='z';ch++){
                    array[i]=ch;
                    String newString=new String(array);
                    if(!set.contains(newString)&&list.contains(newString)){
                        set.add(newString);
                        q.offer(newString);
                        if(newString.equals(end))return len+1;
                    }
                }
                array[i]=old;
            }
        }
        return 0;
    }
}

有向图的完全联通

题目描述

给定一个有向图,包含 N 个节点,节点编号分别为 1,2,...,N。现从 1 号节点开始,如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。

输入描述

第一行包含两个正整数,表示节点数量 N 和边的数量 K。 后续 K 行,每行两个正整数 s 和 t,表示从 s 节点有一条边单向连接到 t 节点。

输出描述

如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。

输入示例

4 4

1 2

2 1

1 3

2 4

输出示例

1

提示信息

从 1 号节点可以到达任意节点,输出 1。

数据范围:

1 <= N <= 100;

1 <= K <= 2000。

思路:

深搜法,如果节点1可以到达节点2,继续看节点2能否到达其他节点,如果节点2能到达其他节点,说明节点1也可以到达这些节点,将这些节点都标记为true。最后遍历所有节点是否都标记为true,如果是的话输出1,否则输出-1。

代码如下:

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

public class Main{
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        int n=in.nextInt();
        int k=in.nextInt();
        int[][] graph=new int[n+1][n+1];
        for(int i=0;i<k;i++){
            int x=in.nextInt();
            int y=in.nextInt();
            graph[x][y]=1;
        }
        boolean[] visited=new boolean[n+1];
        visited[1]=true;
        dfs(graph,visited,1,n);
        for(int i=1;i<=n;i++){
            if(visited[i]==false){
                System.out.println(-1);
                return;
            }
        }
        System.out.println(1);
    }
    public static void dfs(int[][] graph,boolean[] visited,int x,int n){
        for(int j=1;j<=n;j++){
            if(graph[x][j]==1&&visited[j]==false){
                visited[j]=true;
                dfs(graph,visited,j,n);
            }
        }
    }
}

其实深搜广搜的难度并不在广搜深搜本身,而是如何应用深搜广搜去解决问题,要想明白这个逻辑。

相关推荐
Jayyih1 分钟前
嵌入式系统学习Day19(数据结构)
数据结构·学习
renhongxia112 分钟前
大模型微调RAG、LORA、强化学习
人工智能·深度学习·算法·语言模型
计算机程序员小杨19 分钟前
计算机专业的你懂的:大数据毕设就选贵州茅台股票分析系统准没错|计算机毕业设计|数据可视化|数据分析
java·大数据
y1y1z23 分钟前
EasyExcel篇
java·excel
DokiDoki之父42 分钟前
多线程—飞机大战排行榜功能(2.0版本)
android·java·开发语言
DdduZe43 分钟前
8.19作业
数据结构·算法
PyHaVolask1 小时前
链表基本运算详解:查找、插入、删除及特殊链表
数据结构·算法·链表
高山上有一只小老虎1 小时前
走方格的方案数
java·算法
whatever who cares1 小时前
Java 中表示数据集的常用集合类
java·开发语言
吧唧霸1 小时前
golang读写锁和互斥锁的区别
开发语言·算法·golang