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,进行访问标记。
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;
}
思路:广搜就是用到对列。
这种广搜,一般都是,首先先放一个元素进入对列,进行队列的初始化。
然后就是一个对列不为空就进行的循环:先把对列的首元素保存,再弹出。把保存到首元素进行操作,把它可以到达的结点用一个循环都找出来,符合条件的就放入对列,并马上进行一些标记操作。
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;(两个岛屿相邻算作一个相邻岛屿)
我这道题,边界条件又错了!!