目錄
- 110. 字串接龍
- 105. 有向圖的完全可達性
- DFS
- BFS
- 106. 島嶼的周長
- 解法一
- 解法二
110. 字串接龍
題目連結:https://kamacoder.com/problempage.php?pid=1183
文章講解:https://programmercarl.com/kamacoder/0110.字串接龍.html
題目狀態:看題解
思路:
-
輸入部分:
- 讀取單詞數量 ( n )。
- 讀取起始單詞
beginStr
和目標單詞endStr
。 - 讀取並儲存單詞集合
strSet
。
-
輔助資料結構:
visitMap
: 記錄每個單詞是否被訪問過,以及路徑長度。queue<string> que
: 用於廣度優先搜尋(BFS)的佇列。
-
演算法流程:
- 將起始單詞
beginStr
放入佇列,並在visitMap
中標記路徑長度為 1。 - 使用 BFS 遍歷單詞:
- 取出佇列的前端單詞
word
,獲取其路徑長度path
。 - 對
word
的每個字元進行替換,生成新單詞newWord
。 - 檢查
newWord
是否為目標單詞endStr
,如果是,輸出路徑長度並結束程式。 - 如果
newWord
在單詞集合中且未被訪問過,將其加入佇列並記錄路徑長度。
- 取出佇列的前端單詞
- 將起始單詞
-
結束條件:
- 如果佇列為空且未找到目標單詞,輸出 0。
程式碼:
#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);
}
// 記錄strSet裡的字串是否被訪問過,同時記錄路徑長度
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. 有向圖的完全可達性
題目連結:https://kamacoder.com/problempage.php?pid=1177
文章講解:https://programmercarl.com/kamacoder/0105.有向圖的完全可達性.html
題目狀態:看題解
DFS
思路:
-
輸入部分:
- 讀取節點數 ( n ) 和邊數 ( m )。
- 讀取每條邊的起點 ( s ) 和終點 ( t ),構建鄰接表
graph
。
-
DFS 函式:
- 引數:
graph
: 圖的鄰接表表示。key
: 當前訪問的節點。visited
: 標記節點是否被訪問過的布林陣列。
- 邏輯:
- 如果當前節點
key
已訪問,直接返回。 - 標記
key
為已訪問。 - 對於
key
的所有鄰接節點,遞迴呼叫dfs
。
- 如果當前節點
- 引數:
-
主函式:
- 初始化圖的鄰接表
graph
。 - 初始化
visited
陣列,大小為 ( n+1 )(因為節點編號從 1 開始)。 - 從節點 1 開始呼叫
dfs
。 - 檢查所有節點是否被訪問:
- 如果有未訪問的節點,輸出
-1
。 - 如果所有節點都訪問過,輸出
1
。
- 如果有未訪問的節點,輸出
- 初始化圖的鄰接表
程式碼:
// dfs 處理當前訪問的節點
#include <iostream>
#include <vector>
#include <list>
using namespace std;
void dfs(const vector<list<int>>& graph, int key, vector<bool>& visited) {
if (visited[key]) {
return;
}
visited[key] = true;
list<int> keys = graph[key];
for (int key : keys) {
// 深度優先搜尋遍歷
dfs(graph, key, visited);
}
}
int main() {
int n, m, s, t;
cin >> n >> m;
// 節點編號從1到n,所以申請 n+1 這麼大的陣列
vector<list<int>> graph(n + 1); // 鄰接表
while (m--) {
cin >> s >> t;
// 使用鄰接表 ,表示 s -> t 是相連的
graph[s].push_back(t);
}
vector<bool> 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;
}
BFS
思路:
-
輸入部分:
- 讀取節點數 ( n ) 和邊數 ( m )。
- 讀取每條邊的起點 ( s ) 和終點 ( t ),構建鄰接表
graph
。
-
BFS 初始化:
- 建立一個布林陣列
visited
用於標記節點是否被訪問。 - 從節點 1 開始,標記為已訪問,並將其加入佇列
que
。
- 建立一個布林陣列
-
BFS 過程:
- 當佇列不為空時,執行以下步驟:
- 取出佇列的前端節點
key
。 - 遍歷
key
的所有鄰接節點:- 如果鄰接節點未被訪問,將其加入佇列並標記為已訪問。
- 取出佇列的前端節點
- 當佇列不為空時,執行以下步驟:
-
訪問檢查:
- 遍歷
visited
陣列,檢查所有節點是否被訪問。 - 如果有未訪問的節點,輸出
-1
。 - 如果所有節點都訪問過,輸出
1
。
- 遍歷
程式碼:
#include <iostream>
#include <vector>
#include <list>
#include <queue>
using namespace std;
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<bool> visited(n + 1, false);
visited[1] = true; // 1 號房間開始
queue<int> que;
que.push(1); // 1 號房間開始
// 廣度優先搜尋的過程
while (!que.empty()) {
int key = que.front(); que.pop();
list<int> 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. 島嶼的周長
題目連結:https://kamacoder.com/problempage.php?pid=1178
文章講解:https://programmercarl.com/kamacoder/0106.島嶼的周長.html
題目狀態:看題解
解法一
思路:
遍歷每一個格,遇到島嶼則計算其上下左右的空格情況。
遍歷整個網格:
如果當前格子是陸地(grid[i][j] == 1),則檢查其四周。
使用方向陣列計算相鄰格子的座標(x,y)。
如果相鄰格子超出邊界或者是水域(grid[x][y] == 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]; // 計算周邊座標x,y
if (x < 0 // x在邊界上
|| x >= grid.size() // x在邊界上
|| y < 0 // y在邊界上
|| y >= grid[0].size() // y在邊界上
|| grid[x][y] == 0) { // x,y位置是水域
result++;
}
}
}
}
}
cout << result << endl;
}
解法二
思路:
計算周長公式。
遍歷網格計算總陸地個數。之後計算其周長:
- 每個陸地格子初始有 4 條邊。
- 每對相鄰陸地共享 2 條邊。
- 因此,周長計算為:sum * 4 - cover * 2。
程式碼:
#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 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;
}