代码随想录第53天 | 图论二三题

字符串接龙

这题的难点在于要如何想到,结合图去求最短路径的问题

字符串接龙

先看一下题目描述:

题目意思是:把开始的字符串,经过一定次数,变为最后的字符串。

规则是:每次转换字母只能抓换一个,且转换的字符串都必须是------在中间的几个字符串相同的

则求这个转化的最小次数

我们可以把所有字符串连接成一个图,最终求这个图从起点到终点的最短路径

那字符串连接的规则是什么呢??

开始字符可以把每个位置转换为其余的25个字母,若这个转化后的字符串在中间出现过(这个操作是判断集合中是否出现过某元素,使用unordered_set<string>会比较好,因为底层实现是哈希查找)------则它俩可连接......
然后既然是需要搜索去求最短路径(使用广搜更便利),则还需要一个数据结构去存储:节点以及到达这个节点的最短路径,显而易见是一个二维的

则使用unordered_map<key,value>,key是string,value是int存储到达该结点的最短路径
既然使用广搜,则还需要定义队列queue<string> q;

分析完所有基本思路,下面就是代码的具体实现

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

int main(){
    string beginStr, endStr, t;
    int n;

    cin>>n;
    cin>>beginStr>>endStr;

    unordered_set<string> s;
    while(n--){
        cin>>t;
        s.insert(t);//记录中间节点,以便于后续查找
    }

    unordered_map<string,int> m;
    queue<string> q;

    m.insert(pair<string, int>(beginStr, 1));//初始化插入开始节点
    q.push(beginStr);//先把这个开始节点放进去

    while(!q.empty()){
        string it=q.front();
        q.pop();

        //开始遍历这个字符串的替换方式
        for(int i=0;i<it.size();i++){
            string st=it;
            for(int j=0;j<26;j++){
                st[i]='a'+j;
                if (st==endStr) {
                    cout << m[it]+1<< endl; // 找到了路径 
                    return 0;
                }

                if(s.find(st)!=s.end()&&m.find(st)==m.end()){//找到!且未被访问过(广搜不可以搜重复的节点)
                  //则需要添加信息
                  m.insert(pair<string, int>(st,m[it]+1));
                  q.push(st);
                }
            }
        }
    }
    cout<<0<<endl;
    return 0;
}

有向图的完全可达性(开始涉及有向图)

有向图的完全可达性

给出一个有向图,则------如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1

具体判断是否到达任何节点的方法是

  1. 进行图的搜索,遍历每个节点,把到达的节点用一个数组visited记录true。

  2. 最终看是否有节点的visited对应为false,则输出-1,否则输出1
    那如何存储这个有向图呢?

  3. 分析使用邻接表还是邻接矩阵(判断方法是看点和边 的数量差距,差距大使用邻接表比较好,差距小则可以用邻接矩阵)

邻接表:

  • vector<vector<int>> graph(n+1)

  • graph[i] 存储从节点 i 出发能直接到达的节点列表

DFS:

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

void dfs(int node, vector<vector<int>>& graph, vector<bool>& visited) {
    visited[node] = true;
    for (int neighbor : graph[node]) {//去遍历node节点可以到达的节点
        if (!visited[neighbor]) {//若未访问则继续进行dfs
            dfs(neighbor, graph, visited);
        }
    }
}

int main() {
    int N, K;
    cin >> N >> K;
    
    vector<vector<int>> graph(N + 1);//邻接表定义
    
    for (int i = 0; i < K; i++) {
        int s, t;
        cin >> s >> t;
        graph[s].push_back(t);//存储进去s可到达t
    }
    
    vector<bool> visited(N + 1, false);//用于判断是否到达过这个节点
    
    // 从1号节点开始DFS
    dfs(1, graph, visited);
    
    // 检查是否所有节点都被访问
    for (int i = 1; i <= N; i++) {
        if (!visited[i]) {
            cout << -1 << endl;
            return 0;
        }
    }
    
    cout << 1 << endl;
    return 0;
}

BFS:

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

int main() {
    int N, K;
    cin >> N >> K;
    
    // 邻接表,节点编号从1到N
    vector<vector<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, false);
    
    // BFS
    queue<int> q;
    q.push(1);//push进去就要处理
    visited[1] = true;//处理为已访问
    
    while (!q.empty()) {
        int node = q.front();
        q.pop();
        
        // 遍历当前节点的所有邻居
        for (int neighbor : graph[node]) {
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                q.push(neighbor);
            }
        }
    }
    
    // 检查是否所有节点都被访问
    for (int i = 1; i <= N; i++) {
        if (!visited[i]) {
            cout << -1 << endl;
            return 0;
        }
    }
    
    cout << 1 << endl;
    return 0;
}

岛屿的周长

岛屿的周长

这题首先分析,单独一个地面的周长是多少?------4,若周围出现地面,则周长减去1

则我们只需要遍历每个地面,求出其周围(上下左右四个方向)是否有地面?有则减去1

因而------实际上不需要dfs或者bfs进行操作

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
 
int main() {
    int n, m;
    cin >> n >> m;
    
    vector<vector<int>> grid(n, vector<int>(m));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> grid[i][j];
        }
    }
    
    int perimeter = 0;
    int dx[] = {0, 0, -1, 1};
    int dy[] = {1, -1, 0, 0};
    
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (grid[i][j] == 1) {
                // 每个陆地格子初始周长贡献为4
                int count = 4;
                
                // 检查四个方向
                for (int k = 0; k < 4; k++) {
                    int ni = i + dx[k];
                    int nj = j + dy[k];
                    
                    // 如果相邻是陆地,减去1
                    if (ni >= 0 && ni < n && nj >= 0 && nj < m && grid[ni][nj] == 1) {
                        count--;
                    }
                }
                
                perimeter += count;
            }
        }
    }
    
    cout << perimeter << endl;
    return 0;
}
相关推荐
西哥写代码6 小时前
基于dcmtk的dicom工具 第十二章 响应鼠标消息实现图像的调窗、缩放、移动
c++·mfc·dicom·dcmtk·vs2017
头发还没掉光光7 小时前
Linux多线程之生产消费模型,日志版线程池
linux·运维·开发语言·数据结构·c++
lkx097887 小时前
笔记C++语言,太焦虑了
前端·c++·笔记
眠りたいです7 小时前
基于脚手架微服务的视频点播系统-脚手架开发部分-FFmpeg,Etcd-SDK的简单使用与二次封装
c++·微服务·云原生·架构·ffmpeg·etcd
星竹晨L19 小时前
C++继承机制:面向对象编程的基石
开发语言·c++
9ilk19 小时前
【仿RabbitMQ的发布订阅式消息队列】--- 模块设计与划分
c++·笔记·分布式·后端·中间件·rabbitmq
恒者走天下20 小时前
面试的时候项目怎么聊,才能发挥最大的价值
c++
阿巴~阿巴~20 小时前
线程局部存储(Thread-Local Storage, TLS)
linux·服务器·开发语言·c++·线程·虚拟地址空间·线程局部存储
杨筱毅21 小时前
【C++】【C++面试】Android SO 体积优化技术点梳理
c++·面试