代码训练营DAY53 第十一章:图论part04

110. 字符串接龙

110. 字符串接龙

题目描述

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

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

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

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

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

  5. beginStr 和 endStr 不在 字典 strList 中

  6. 字符串中只有小写的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

思路

以示例1为例,从这个图中可以看出 abc 到 def的路线 不止一条,但最短的一条路径上是4个节点。

本题只需要求出最短路径的长度就可以了,不用找出具体路径。

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

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

在搜索的过程中,我们可以枚举,用26个字母替换当前字符串的每一个字符,在看替换后 是否在 strList里出现过,就可以判断 两个字符串 是否是链接的。所以判断点与点之间的关系,需要判断是不是差一个字符,如果差一个字符,那就是有链接

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

求起点和终点的最短路径长度,在无权图中,求最短路,用深搜或者广搜就行,没必要用最短路算法。

在无权图中,用广搜求最短路最为合适,广搜只要搜到了终点,那么一定是最短的路径。因为广搜就是以起点中心向四周扩散的搜索。

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <unordered_map>
#include <queue>
using namespace std;
int main(){
    string beginStr,endStr,str;
    int n;
    cin>>n;
    unordered_set<string> strSet;
    cin>>beginStr>>endStr;
    for(int i=0;i<n;i++){
        cin>>str;
        strSet.insert(str);
    }
    unordered_map<string,int> visitMap;

    queue<string> que;
    que.push(beginStr);

    visitMap.insert(pair<string,int>(beginStr,1));

    while(!que.empty()){
        string word=que.front();
        que.pop();
        int path=visitMap[word];

        for(int i=0;i<word.size();i++){
            string newword=word;

            for(int j=0;j<26;j++){
                newword[i]=j+'a';
                if(newword==endStr){
                    cout<<path+1<<endl;
                    return 0;
                }
                if(strSet.find(newword)!=strSet.end()&&visitMap.find(newword)==visitMap.end()){
                    visitMap.insert(pair<string,int>(newword,path+1));
                    que.push(newword);
                }
            }
        }
    }
    cout<<0<<endl;
}

105.有向图的完全联通

105. 有向图的完全联通

【题目描述】

给定一个有向图,包含 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、确认递归函数,参数

需要传入地图,需要知道当前我们拿到的key,以至于去下一个房间。

同时还需要一个数组,用来记录我们都走过了哪些房间,这样好知道最后有没有把所有房间都遍历的,可以定义一个一维数组。

2、确认终止条件

在递归中,本方法**处理当前访问的节点,**当前访问的节点如果是 true ,说明是访问过的节点,那就终止本层递归,如果不是true,我们就把它赋值为true,因为这是我们处理本层递归的节点。

3、处理目前搜索节点出发的路径

**本题就没有回溯,**本题是需要判断 1节点 是否能到所有节点,那么我们就没有必要回溯去撤销操作了,只要遍历过的节点一律都标记上。

什么时候需要回溯操作呢?

当我们需要搜索一条可行路径的时候,就需要回溯操作了,因为没有回溯,就没法"调头", 如果不理解的话,去看我写的 0098.所有可达路径 的题解。

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

void dfs(const vector<list<int>>& graph,int key,vector<bool>& visited){
    if(visited[key])return;
    visited[key]=true;
    list<int> keys=graph[key];
    for(int i:keys){
        dfs(graph,i,visited);
    }
}
int main(){
    int n,m,s,t;
    cin>>n>>m;
    vector<list<int>> graph(n+1);
    while(m--){
        cin>>s>>t;
        graph[s].push_back(t);
    }
    vector<bool> visited(n+1,false);
    dfs(graph,1,visited);
    for(int i=1;i<=n;i++){
        if(visited[i]==false){
            cout<<-1<<endl;
            return 0;
        }
    }
    cout<<1<<endl;
}

106. 岛屿的周长

106. 岛屿的周长

题目描述

给定一个由 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

遍历每一个空格,遇到岛屿则计算其上下左右的空格情况。

如果该陆地上下左右的空格是有水域,则说明是一条边,

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;

}
相关推荐
凤年徐14 分钟前
【数据结构与算法】刷题篇——环形链表的约瑟夫问题
c语言·数据结构·c++·算法·链表
张子夜 iiii27 分钟前
机器学习算法系列专栏:逻辑回归(初学者)
人工智能·算法·机器学习·逻辑回归
vivo互联网技术27 分钟前
慢SQL优化实战:从一例线上慢SQL探究执行引擎工作过程
数据库·mysql·算法
我想吃烤肉肉31 分钟前
leetcode-python-删除链表的倒数第 N 个结点
python·算法·leetcode·链表
flashlight_hi1 小时前
LeetCode 分类刷题:16. 最接近的三数之和
javascript·数据结构·算法·leetcode
彭军辉1 小时前
什么是抽象主义人工智能?
人工智能·算法·语言模型·机器人
是店小二呀1 小时前
【动态规划 | 01背包】动态规划经典:01背包问题详解
算法·动态规划
黑色的山岗在沉睡2 小时前
P10480 可达性统计
数据结构·算法
魏嗣宗2 小时前
缓存系统扩展思考详解
前端·算法·架构