有向图的访问
1.对于深度优先遍历的设计不熟悉,什么时候该递归,什么时候该终止,很多思考没有弄明白 2.对于邻接表图应用并不熟练,很多粗疏的地方,比如应该事先同样申请n+1的空间。 3.visit传参应当使用引用,同时应该注意是bool类型还是int类型
#include<iostream>
#include<vector>
#include<list>
using namespace std;
// 深度优先搜索:标记从key出发能到达的所有节点
// 参数:graph(邻接表,引用传递避免复制)、visit(访问标记,引用传递)、key(当前节点)
void dfs(vector<list<int>>& graph, vector<bool>& visit, int key) {
// 标记当前节点为已访问
visit[key] = true;
// 获取当前节点的邻接表(引用避免复制)
list<int>& neighbors = graph[key];
// 遍历所有邻接节点
for (int next_node : neighbors) {
if (!visit[next_node]) { // 仅访问未访问的节点
dfs(graph, visit, next_node);
}
}
}
int main() {
// 输入节点数量n、边的数量k
cout << "输入结点数量和边的数量(空格分隔):" << endl;
int n, k;
cin >> n >> k;
// 初始化邻接表:大小为n+1(节点从1到n编号)
vector<list<int>> graph(n + 1);
cout << "输入" << k << "条边(每条边两个节点s t,空格分隔):" << endl;
for (int i = 0; i < k; i++) {
int s, t;
cin >> s >> t;
graph[s].push_back(t); // 添加s→t的边
graph[t].push_back(s); // 【关键】如果是无向图,必须添加t→s的边;若为有向图可删除此行
}
// 初始化访问标记数组:大小n+1,初始值false
vector<bool> visit(n + 1, false);
// 从节点1开始DFS
dfs(graph, visit, 1);
// 检查是否所有节点都被访问
bool all_visited = true;
for (int i = 1; i <= n; i++) {
if (!visit[i]) {
all_visited = false;
break;
}
}
// 输出结果
if (all_visited) {
cout << 1 << endl;
} else {
cout << -1 << endl;
}
return 0; // 正常结束返回0
}
采用bfs时怎么入队,出队要思考
#include<iostream>
#include<vector>
#include<list>
#include<queue> // 【关键】添加queue头文件
using namespace std;
int main() {
// 输入节点数量n、边的数量k
cout << "输入结点数量和边的数量(空格分隔):" << endl;
int n, k;
cin >> n >> k;
// 初始化邻接表:大小为n+1(节点从1到n编号)
vector<list<int>> graph(n + 1);
cout << "输入" << k << "条边(每条边两个节点s t,空格分隔):" << endl;
for (int i = 0; i < k; i++) {
int s, t;
cin >> s >> t;
graph[s].push_back(t); // 添加s→t的边
graph[t].push_back(s); // 【关键】无向图需双向添加边;有向图可删除此行
}
// 初始化访问标记数组:大小n+1,初始值false
vector<bool> visit(n + 1, false);
// 从节点1开始BFS
queue<int> que;
visit[1] = true; // 【关键】入队前先标记起始节点为已访问
que.push(1); // 【关键】queue入队用push(),不是push_back()
// 执行BFS
while (!que.empty()) {
// 出队获取当前节点
int key = que.front();
que.pop();
// 获取当前节点的邻接表(const引用避免复制)
const list<int>& neighbors = graph[key];
// 遍历所有邻接节点
for (int cur : neighbors) {
if (!visit[cur]) { // 仅访问未访问的节点
visit[cur] = true; // 入队前先标记,避免重复入队
que.push(cur); // 入队
}
}
}
// 检查是否所有节点都被访问
bool all_visited = true;
for (int i = 1; i <= n; i++) {
if (!visit[i]) {
all_visited = false;
break;
}
}
// 输出结果
if (all_visited) {
cout << 1 << endl;
} else {
cout << -1 << endl;
}
return 0; // 正常结束返回0
}
字符串问题:
1.需要运用hash表快速查找映射 2.对于传参和返回值要有考虑
//思路:将每个字符串视作一个结点,存在单个字符相互转换关系的字符串存在联通关系
//可以通过图的遍历算法求得结果,采用广度优先搜索可以最快获得最短路径,不需要多次比较
//步骤:1.将字符串映射至hash表方便快速查找
//2.通过不断变换字符串的单个字符,并在hash表中寻找联通字符串
//3.找到下一个联通字符串之后存入数组并标记,继续重复,直到查找到目标字符串或遍历完毕
#include<iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <unordered_map>
#include <queue>
using namespace std;
int main(){
//读入字符串
int N;
cout<<"输入字符串数量"<<endl;
cin>>N;
//使用hash表存储字符串字典
unordered_set<string> strList;
//输入起始字符串和终止字符串
string beginStr;
string endStr;
cin>>beginStr>>endStr;
//读入字典
string str;
for(int i=1;i<=N;i++){
cin>>str;
strList.insert(str);
}
// 记录strSet里的字符串是否被访问过,同时记录路径长度
unordered_map<string, int> visitMap; // <记录的字符串,路径长度>
// 初始化队列
queue<string> que;
que.push(beginStr);
//初始化visitMap,方便快速查找迭代
visitMap.insert(pair<string, int>(beginStr, 1));
//开始广度优先搜索
while(!que.empty()){
//出队
string cur=que.front();
que.pop();
int path = visitMap[word]; // 这个字符串在路径中的长度
//逐一替换字符串字符,并开始在strList中比对寻找,如果满足条件,插入visitMap中
for(int i=0;i<cur.size();i++){
for(int j=0;j<26;j++){
string newWord=cur;
//将第i个字符替换
newWord[i]=j+'a';
//判断是否为endStr
if (newWord == endStr) { // 发现替换字母后,字符串与终点字符串相同
cout << path + 1 << endl; // 找到了路径
return 0;
}
//如果不是endStr,则在strList中进行比对
if(strList.find(newWord)!=strList.end()&&visitMap.find(newWord)=visitMap.end()){//在词典中可查找到,且未被访问
visitMap.insert(pair<string, int>(newWord, path + 1));//插入到词典当中
que.push(newWord);//执行入队
}
}
}
}
//循环执行完毕之后未查找到,则返回0
cout<<0<<endl;
return 0;
}