【算法打卡day7(2026-02-12 周四)算法:BFS and BFS】10__卡码网110_字符串迁移, 11_卡码网105_有向图的完全连通

- 第 166 篇 -
Date: 2026 - 02- 12 | 周四
Author: 郑龙浩(仟墨)

2026-02-12 周四 | 算法打卡day7

文章目录

10__卡码网110_字符串迁移

题目描述

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

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

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

  3. 每次转换只能改变一个字符。

  4. 转换过程中的中间字符串必须是字典 strList 中的字符串,且strList里的每个字符串只用使用一次。

给你两个字符串 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

思路:

这道题没有说点与点之间是如何连接的,需要我们自己去处理点与点之间的连接

最大的疑惑:如何知道 某个字符串 连接的 是哪个字符串呢?

或者说,如何知道A点连接的是什么点?

BFS:

a. 初始化队列,将beginStr入队

b. 初始化visited[beginStr] = 1(起点本身算第一个节点)

c. 当队列不为空时循环

  • 使用unordered_set <strng> set去存储 strList(用于O(1)时间判断字符串是否存在)
  • unordered_set <strng, int> visited记录每个字符串是否被访问过以及从起点到该字符串的路径长度
  • 然后使用26个字母轮番去替换每一个字符,存入new_word,判断new_word在strList中是否存在,
  • 如果new_word == endStr,直接返回path + 1(找到终点)
  • 如果newWordstrSet中存在 没有被访问过:
    • visited[newWord] = path + 1
    • newWord入队

本题是个无权图,使用深搜或者广搜就可以
建议使用BFS,因为BFS是一圈一圈去搜索,只要搜到了终点,就一定是最短路径
如果用DFS,会直接搜到最底,还要判断哪个是最短路径

【我的疑惑】:

同一个节点可能被从不同路径多次访问,并且这些路径的长度(如2和3)可能不同。但是BFS只记录了第一次访问时的路径长度(比如3),但后续存在一条更短的路径(比如2),那么path值记录的最短路径长度不就出错了吗?

  1. BFS是按层搜索,回显搜索所有距离为1的节点(第一层),假设是个波纹,也就是一个节点第一次被波纹触碰到时,它所在的"圈数"就是它距离起点的最短距离。
  2. 也就是一个节点,无论从哪条路径访问,都是属于同一层的,也就是长度都是一样的,所以,只需要记录第一次访问时的长度就可以了

【我的代码】

cpp 复制代码
// Date: 2026-02-12 周四 Author:郑龙浩
// 10_卡码网110_字符串迁移
// 算法:BFS
#include "bits/stdc++.h"
using namespace std;

string beginStr, endStr;
unordered_set <string> strList;

int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    
    int N; cin >> N;
    cin >> beginStr >> endStr;
    string word;
    // 将所有str存入strList中去
    for (int i = 0; i < N; i ++) {
        cin >> word;
        strList.insert(word);
    }

    int path = 1; // 到达某节点word的最短长度
    unordered_map <string, int> visited; // 存放访问过的String节点 到该节点的路径长度
    visited.insert({beginStr, path});
    queue <string> que;
    que.push(beginStr); // 将第一个string节点存入que

    // 启用BFS --> 不搜索当前word,而是搜索word的下一个new_word
    // 也就是不对word进行判断,因为在que.push(new_word)前已经对其new_word合理性进行了
    while (!que.empty()) {
        
        string word = que.front(); // 取出que中当前处理的String
        que.pop(); // 去掉front的char

        // 【注意】我刚开始忘记写了
        path = visited[word]; // 将path更新为到达word节点的最近的长度

        int len = word.size(); //word 字符串 size
        // 尝试替换每个字符(用26个字符依次替换某个字符)
        // 替换索引i字符
        for (int i = 0; i < len; i++) {
            string new_word = word; // 存放新组成的单词
            for (int j = 0; j < 26; j++) { // 每次只改变i处字符
                new_word[i] = j + 'a';
                if (new_word == endStr) { //如果找到了终点,此时就是最短路径
                    cout << path + 1;
                    return 0;
                    // 如果new_word在strList中 && 没访问过,就加入que中去,且标记为访问过+记录到该节点的路径长度
                } else if (strList.find(new_word) != strList.end() && visited.find(new_word) == visited.end()){ 
                    que.push(new_word); // 将new_wor放入que待处理中
                    visited.insert({new_word, path + 1}); // 将new_word标记为访问过,并且记录到new_word这个节点的最短路径

                }
            }
        }

    }

    cout << 0; // 如果beginStr无法转换为endstring才会直接输出0
    return 0;
}

11_卡码网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 <= N <= 100;

1 <= K <= 2000。

cpp 复制代码
// Date: 2026-02-12 周四 Author:郑龙浩
// 11_卡码网105_有向图的完全连通
// 算法:BFS

// 思路:
// 使用BFS或者DFS,从节点1搜索到节点N,只要搜索过,就用visied标记一下。\
最后遍历所有节点,如果visited中有false, 就是存在没有访问的节点,就输出-1,如果全都是true,就输出1
// 因为本题可能会出现节点多边少的情况,所以使用邻接表
// 如果使用矩阵,可能会存在浪费空间的情况

#include "bits/stdc++.h"
using namespace std;

// 从1开始搜索,直到最后
void dfs(vector <list <int>>&  graph, vector <bool>& visited, int cur) {
    if (visited[cur] == true) { // 如果当前节点访问过,就return
        return;
    }
    
    visited[cur] = true; // 只要传入了cur且没访问过,既要将其标记访问

    // 找到cur的下一个节点
    list <int> nexts = graph[cur]; // 将cur连接的所有节点取出
    for (int next : nexts) {
        if (visited[next] == false) { // 如果next节点没被访问过,就dfs一下
            dfs(graph, visited, next);
        }
    }
}

int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    
    int N, K;
    cin >> N >> K;

    vector <list <int>> graph(N + 1); // 邻接表

    int s, t;
    while (K--) {
        cin >> s >> t;
        graph[s].push_back(t);  // 节点s可以指向节点t
    }

    vector <bool> visited(N + 1); // 访问过的
    dfs(graph, visited, 1); // 使用dfs搜索所有连接的节点

    for (int i = 1; i <= N; i++) {
        // 只要有一个节点没有访问过,就直接输出-1,且return
        if (visited[i] == false) {
            cout << -1; return 0;
        }
    }
    
    // 只要全都访问过,就会走到这一步,直接输出1
    cout << 1;
    return 0;
}
相关推荐
935962 小时前
机考24 翻译18 单词11
c语言·数据结构·算法
爱思德学术2 小时前
中国计算机学会(CCF)推荐学术会议-B(计算机体系结构/并行与分布计算/存储系统):SPAA 2026
算法
2 小时前
2.12矩阵问题,发牌,数字金字塔
线性代数·算法·矩阵
无聊的小坏坏2 小时前
一文讲通:二分查找的边界处理
数据结构·c++·算法
m0_528749002 小时前
C语言错误处理宏两个比较重要的
java·linux·算法
TracyCoder1233 小时前
LeetCode Hot100(50/100)——153. 寻找旋转排序数组中的最小值
算法·leetcode·职场和发展
诸葛务农3 小时前
点云配准在人形机器人中的应用:ICP算法(2)
人工智能·算法·机器学习·机器人
摘星编程3 小时前
**解锁Agent智能体新纪元:自主协作、任务分解与人类意图对齐的终极指南**
算法
mmz12073 小时前
逆序对问题(c++)
c++·算法