字符串接龙
这题的难点在于要如何想到,结合图去求最短路径的问题
先看一下题目描述:

题目意思是:把开始的字符串,经过一定次数,变为最后的字符串。
规则是:每次转换字母只能抓换一个,且转换的字符串都必须是------在中间的几个字符串相同的
则求这个转化的最小次数
我们可以把所有字符串连接成一个图,最终求这个图从起点到终点的最短路径
那字符串连接的规则是什么呢??
开始字符可以把每个位置转换为其余的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
具体判断是否到达任何节点的方法是
进行图的搜索,遍历每个节点,把到达的节点用一个数组visited记录true。
最终看是否有节点的visited对应为false,则输出-1,否则输出1
那如何存储这个有向图呢?分析使用邻接表还是邻接矩阵(判断方法是看点和边 的数量差距,差距大使用邻接表比较好,差距小则可以用邻接矩阵)
邻接表:
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;
}