代码随想录–图论部分
day 54 图论第四天
一、卡码网110–字符串接龙
代码随想录题目链接:代码随想录
字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列:
序列中第一个字符串是 beginStr。
序列中最后一个字符串是 endStr。
每次转换只能改变一个字符。
转换过程中的中间字符串必须是字典 strList 中的字符串,且strList里的每个字符串只用使用一次。
给你两个字符串 beginStr 和 endStr 和一个字典 strList,找到从 beginStr 到 endStr 的最短转换序列中的字符串数目。如果不存在这样的转换序列,返回 0。
实际上就是构建了一个无向图,要求寻找起点到终点的最短路径长度
明显要用广度优先搜索,因为这样做只要搜到了就是最短的
唯一难点是这里用字符字典在操作,需要额外地设置搜索方式
用unordered_set存这些字符串,对每个词进行变换搜索即可找到图节点之间的连接
代码如下:
#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
visitMap.insert(pair<string, int>(beginStr, 1));
while(!que.empty()) {
string word = que.front();
que.pop();
int path = visitMap[word]; // 这个字符串在路径中的长度
// 开始在这个str中,挨个字符去替换
for (int i = 0; i < word.size(); i++) {
string newWord = word; // 用一个新字符串替换str,因为每次要置换一个字符
// 遍历26的字母
for (int j = 0 ; j < 26; j++) {
newWord[i] = j + 'a';
if (newWord == endStr) { // 发现替换字母后,字符串与终点字符串相同
cout << path + 1 << endl; // 找到了路径
return 0;
}
// 字符串集合里出现了newWord,并且newWord没有被访问过
if (strSet.find(newWord) != strSet.end()
&& visitMap.find(newWord) == visitMap.end()) {
// 添加访问信息,并将新字符串放到队列中
visitMap.insert(pair<string, int>(newWord, path + 1));
que.push(newWord);
}
}
}
}
// 没找到输出0
cout << 0 << endl;
}
二、卡码网105–有向图的完全可达性
代码随想录题目链接:代码随想录
给定一个有向图,包含 N 个节点,节点编号分别为 1,2,…,N。
现从 1 号节点开始,如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。
实际上只需要定义一个visited数组,记录每个点是否被访问过即可
做一个深度搜索,代码如下:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
void dfs(vector<list<int>> & graph, int key, vector<int> & visited)
{
if(visited[key] == 1) return;
visited[key] = 1;
auto keys = graph[key];
for(auto key : keys) dfs(graph, key, 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<int> visited(n + 1, 0);
dfs(graph, 1, visited);
visited[0] = 1;
for(auto ele : visited)
{
if(ele == 0)
{
cout << -1 << endl;
return 0;
}
}
cout << 1 << endl;
}
三、卡码网106–岛屿的周长
代码随想录题目链接:代码随想录
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。
你可以假设矩阵外均被水包围。在矩阵中恰好拥有一个岛屿,假设组成岛屿的陆地边长都为 1,请计算岛屿的周长。岛屿内部没有水域。
这个题不需要深度或者广度搜索,只需要遍历一下,每个元素周围是否在图的边界或者满足1->0的变化,满足则周长+1
代码如下:
#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];
if(x < 0 || y < 0 || x >= n || y >= m || !grid[x][y]) result ++;
}
}
}
cout << result << endl;
}
不过也有关联,判断处很像深搜的边界判断语句