代码随想录训练营Day 67|卡码网110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长

1.字符串接龙

110. 字符串接龙 | 代码随想录

代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int main(){
    // 输入
    string beginStr,endStr,str;
    int n;
    cin >> n;
    unordered_set  strSet;
    cin >> beginStr >> endStr;
    for(int i = 0; i < n; i++){
        cin >> str;
        strSet.insert(str);
    }
    // 处理
    unordered_map visitMap; // <记录的字符串,字符串长度>
    // 初始化对列 广搜只要搜到,一定是最短路径
    queue que;
    que.push(beginStr);
    // 初始化visitMap
    visitMap.insert(pair(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; // 替换后的字符串用newWord来储存
            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(newWord,path + 1));
                    que.push(newWord);
                }
            }
        }
    }
    // 如果没有找到结果
    cout << 0 << endl;
}

 思路:

        首先要知道 广搜只要搜到结果,这个结果的路径就是最短的。这道题正适合用广搜来解决。

        只要将一个元素添加进队列中,就对其进行访问标记。

        我们首先将对列的第一个元素取出,并将其路径加1。然后在这个字符串上进行改动,对每一位依次进行改动,可以将其遍历26个英文字母。

        如果改动后的字符串已经是结果字符串了,就将结果path+1进行输出;

        如果不是结果,就去看看这个改动后的字符串是否在字典里。如果在,就将其加入队列,并将其路径加1,进行访问标记。

2.有向图的完全可达性

 105.有向图的完全可达性 | 代码随想录

代码:(dfs深搜 处理当前要访问的结点)

#include 
#include 
#include 
using namespace std;
void dfs(vector> &graph,int key,vector &visited){
    if(visited[key]) return;
    visited[key] = true;
    list keys = graph[key];
    for(int key:keys){
        dfs(graph,key,visited);
    }
}
int main(){
    // 输入
    int n,k,s,t;
    cin >> n >> k;
    vector> graph(n + 1);
    while(k--){
        cin >> s >> t;
        graph[s].push_back(t);
    }
    // 处理
    vector 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;
}

代码:(dfs深搜 处理下一个要访问的结点) 

#include 
#include 
#include 
using namespace std;
void dfs(vector> &graph,int key,vector &visited){
    list keys = graph[key];
    for(int key:keys){
        if(visited[key]) continue;
        visited[key] = true;
        dfs(graph,key,visited);
    }
}
int main(){
    // 输入
    int n,k,s,t;
    cin >> n >> k;
    vector> graph(n + 1);
    while(k--){
        cin >> s >> t;
        graph[s].push_back(t);
    }
    // 处理
    vector visited(n + 1,false);
    visited[1] = true;
    dfs(graph,1,visited);
    // 输出
    for(int i = 1; i <= n; i++){
        if(visited[i] == false){
            cout << -1 << endl;
            return 0;
        }
    }
    cout << 1 << endl;
}

 思路:

        岛屿问题是直接给了二维数组,用1来表示陆地。这里这种给点和边,要自己构造邻接表或邻接矩阵的,就要注意给的结点和边都是从1开始的,为了和题上的数字对应上,自己构造的长度多留一个,留到n+1。

        这道题题上问的是从结点1开始,是否能到达所有的点。所以我们visited数组只要记录N+1个点是否被访问就好了,不用定义成二维的了。

        在深搜的两种写法中,终止条件的有无取决于你是处理当前访问的结点,还是下一个要访问的结点。

遍历的时候,什么时候终止呢?

这里有一个很重要的逻辑,就是在递归中,我们是处理当前访问的节点,还是处理下一个要访问的节点

这决定 终止条件怎么写。

首先明确,本题中什么叫做处理,就是 visited数组来记录访问过的节点,该节点默认 数组里元素都是false,把元素标记为true就是处理 本节点了。

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

 代码:(bfs 广搜)

#include 
#include 
#include 
#include 
using namespace std;
int main() {
    int n, m, s, t;
    cin >> n >> m;

    vector> graph(n + 1);
    while (m--) {
        cin >> s >> t;
        graph[s].push_back(t);

    }
    vector visited(n + 1, false);
    queue que;
    que.push(1);
    visited[1] = true;
    while(!que.empty()){
        int key = que.front();
        que.pop();
        list keys = graph[key];
        for(int key:keys){
            if(!visited[key]){
                que.push(key);
                visited[key] = true;
            }
        }
    }

    for (int i = 1; i <= n; i++) {
        if (visited[i] == false) {
            cout << -1 << endl;
            return 0;
        }
    }
    cout << 1 << endl;
}

思路:广搜就是用到对列。

这种广搜,一般都是,首先先放一个元素进入对列,进行队列的初始化。

然后就是一个对列不为空就进行的循环:先把对列的首元素保存,再弹出。把保存到首元素进行操作,把它可以到达的结点用一个循环都找出来,符合条件的就放入对列,并马上进行一些标记操作。

3.岛屿的周长 

106. 岛屿的周长 | 代码随想录

代码: 

#include 
#include 
using namespace std;
int main(){
    // 输入
    int n,m;
    cin >> n >> m;
    vector> grid(n,vector(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;
}

思路:遇见岛屿问题不要养成定势思维,认为一定要用dfs或bfs,这道题求周长,就是很简单的计算题。

周长=岛屿方格数*4 - 相邻岛屿数*2;(两个岛屿相邻算作一个相邻岛屿)

我这道题,边界条件又错了!!

你可能感兴趣的:(一刷代码随想录,算法,c++,数据结构,深度优先,图论)