图论篇--代码随想录算法训练营第五十三天打卡| 110. 字符串接龙,105.有向图的完全可达性,106. 岛屿的周长

110. 字符串接龙

题目链接:110. 字符串接龙

题目描述:

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

  1. 序列中第一个字符串是 beginStr。
  2. 序列中最后一个字符串是 endStr。
  3. 每次转换只能改变一个字符。
  4. 转换过程中的中间字符串必须是字典 strList 中的字符串,且strList里的每个字符串只用使用一次。

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

解题思路:

这道题要解决两个问题:

  • 图中的线是如何连在一起的
  • 起点和终点的最短路径长度

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

2)求起点和终点的最短路径长度,这里无向图求最短路,广搜最为合适,广搜只要搜到了终点,那么一定是最短的路径。因为广搜就是以起点中心向四周扩散的搜索。

另外需要有一个注意点:

  • 本题是一个无向图,需要用标记位,标记着节点是否走过,否则就会死循环!
  • 使用set来检查字符串是否出现在字符串集合里更快一些

代码:

cpp 复制代码
#include<iostream>
#include<unordered_set>
#include<queue>
#include<unordered_map>
#include<string>
using namespace std;

int main()
{
    int n;
    cin >> n;
    unordered_set<string> strList;
    string beginStr, endStr;
    cin >> beginStr >> endStr;
    for(int i = 0; i < n; i++) 
    {
        string s;
        cin >> s;
        strList.insert(s);
    }
    unordered_map<string,int> visitStr;
    queue<string> q;
    q.push(beginStr);
    visitStr.insert({beginStr,1});
    while(!q.empty())
    {
        string val = q.front();
        q.pop();
        int path = visitStr[val];
        for(int i = 0; i < val.size(); i++)
        {
            string newStr = val;
            for(int j = 0; j < 26; j++)
            {
                newStr[i] = j + 'a';
                if(newStr == endStr)
                {
                    cout << path + 1 << endl;
                    return 0;
                }
                if(visitStr.find(newStr) == visitStr.end() && strList.find(newStr) != strList.end())
                {
                    visitStr[newStr] = path + 1;
                    q.push(newStr);
                }
            }
        }
    }
    
    cout << 0 << endl;
    return 0;
}

105.有向图的完全可达性

题目链接:105. 有向图的完全可达性

题目描述:

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

解题思路:

使用数组visited来保存当前节点的访问情况,使用dfs来遍历所有节点。最后如果所有节点均被访问,则输出1。

代码:

cpp 复制代码
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;

void dfs(vector<list<int>>& graph,vector<bool>& visited,int key)
{
    if(visited[key]) return;
    visited[key] = true;
    for(auto x : graph[key])
        dfs(graph,visited,x);
}

int main()
{
    int n,k;
    cin >> n >> k;
    vector<list<int>> graph(n+1);
    for(int i = 0; i < k ; i++)
    {
        int s,t;
        cin >> s >> t;
        graph[s].push_back(t);
    }
    
    vector<bool> visited(n+1);
    dfs(graph,visited,1);
    for(int i = 1; i <= n; i++) 
        if(visited[i] == false) 
        {
            cout << -1 << endl;
            return 0;
        }
    cout << 1 << endl;
    return 0;
}

106. 岛屿的周长

题目链接:106. 岛屿的周长

题目描述:

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

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

解题思路:

1)找边法

遍历每一个空格,遇到岛屿则计算其上下左右的空格情况。如果该陆地上下左右的空格是有水域,则说明是一条边;如果该陆地上下左右的空格出界了,则说明是一条边;

2)公式法

结果 result = 岛屿数量 * 4 - cover * 2;

有一对相邻两个陆地,边的总数就要减2

每次只统计节点上边相邻陆地和其左边相邻陆地,其余方向不统计防止重复。

代码:

1)dfs找边法

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
 
int cnt = 0;
int dx[4] = {-1,0,0,1};
int dy[4] = {0,-1,1,0};
 
void dfs(vector<vector<int>>& grid,vector<vector<bool>>& visited,int r, int c)
{
    visited[r][c] = true;
    for(int i = 0 ; i < 4; i++)
    {
        int x = r + dx[i], y = c + dy[i];
        if(x < 0 || y < 0 || x >= grid.size() || y >= grid[0].size() || grid[x][y] == 0)
        {
            cnt++;
            continue;
        }
        if(grid[x][y] == 1 && !visited[x][y])
            dfs(grid,visited,x,y);
    }
}
 
int main()
{
    int n,m;
    cin >> n >> m;
    vector<vector<int>> grid(n,vector<int>(m));
    vector<vector<bool>> visited(n,vector<bool>(m));
    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            cin >> grid[i][j];
    for(int i = 0 ; i < n; i++)
        for(int j = 0; j < m; j++)
            if(grid[i][j] == 1 && !visited[i][j])
            {
                dfs(grid,visited,i,j);
                break;
            }
                 
    cout << cnt << endl;
    return 0;
}

2)直接找边法

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> grid(n, vector<int>(m, 0));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> grid[i][j];
        }
    }
    int direction[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
    int result = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (grid[i][j] == 1) {
                for (int k = 0; k < 4; k++) {       // 上下左右四个方向
                    int x = i + direction[k][0];
                    int y = j + direction[k][1];    // 计算周边坐标x,y
                    if (x < 0                       // x在边界上
                            || x >= grid.size()     // x在边界上
                            || y < 0                // y在边界上
                            || y >= grid[0].size()  // y在边界上
                            || grid[x][y] == 0) {   // x,y位置是水域
                        result++;
                    }
                }
            }
        }
    }
    cout << result << endl;
 
}

3)公式法

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> grid(n, vector<int>(m, 0));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> grid[i][j];
        }
    }
    int sum = 0;    // 陆地数量
    int cover = 0;  // 相邻数量
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (grid[i][j] == 1) {
                sum++; // 统计总的陆地数量
                // 统计上边相邻陆地
                if(i - 1 >= 0 && grid[i - 1][j] == 1) cover++;
                // 统计左边相邻陆地
                if(j - 1 >= 0 && grid[i][j - 1] == 1) cover++;
                // 为什么没统计下边和右边? 因为避免重复计算
            }
        }
    }

    cout << sum * 4 - cover * 2 << endl;

}
相关推荐
cherry_rainyyy14 分钟前
力扣整理版九:贪心算法(待整理)
算法·leetcode·贪心算法
深思慎考25 分钟前
计算机操作系统——进程控制(Linux)
linux·服务器·c++·c
捕鲸叉43 分钟前
C++设计模式之组合模式实践原则
c++·设计模式·组合模式
阿熊不会编程1 小时前
【计网】自定义协议与序列化(一) —— Socket封装于服务器端改写
linux·开发语言·网络·c++·设计模式
碧海蓝天20221 小时前
接上一主题,C++14中如何设计类似于std::any,使集合在C++中与Python一样支持任意数据?
开发语言·c++·python
醉颜凉2 小时前
计算(a+b)/c的值
java·c语言·数据结构·c++·算法
zl.rs2 小时前
对比C++,Rust在内存安全上做的努力
c++·安全·rust
机器视觉知识推荐、就业指导2 小时前
Qt/C++基于重力模拟的像素点水平堆叠效果
c++·qt
武昌库里写JAVA2 小时前
SpringCloud+SpringCloudAlibaba学习笔记
java·开发语言·算法·spring·log4j
小咖拉眯3 小时前
第十六届蓝桥杯模拟赛第二期题解—Java
java·数据结构·算法·蓝桥杯·图搜索算法