圖論:搜索問題

提到圖論中的搜索問題,首先想到的也就是DFS和BFS了,而提到這兩種搜索,那么最典型的題目就是島嶼問題了,下面就練習幾道相關的題目,為之后的更深奧的圖論學習打下基礎!

孤島的總面積

題目鏈接:孤島的總面積

這道題,顧名思義就是求孤島的面積之和,所謂的孤島就是地圖中間的島嶼,也就是需要將地圖邊界上的島嶼不考慮,那怎么不考慮呢?很簡單,我們只需要遍歷地圖的四個邊界,然后遇到一個陸地就用DFS將與之相連的所有陸地變為海洋即可,然后遍歷一遍地圖,如果還有陸地的話那么他,就是孤島了,因為要求總面積,所以遇到一個陸地就將面積++即可。

//https://kamacoder.com/problempage.php?pid=1173
//孤島的總面積
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define pii pair<int,int>
#define fi first
#define se second
const int N = 55;
vector<vector<int>> mp(N,vector<int>(N));
int n,m,ans=0;
void pre_handle()
{}
int dis[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};void dfs(int x,int y)
{mp[x][y] = 0;for(int i=0;i<4;i++){int tx = x + dis[i][0];int ty = y + dis[i][1];if(tx < 1 || tx > n || ty < 1 || ty > m) continue;if(mp[tx][ty] == 1) dfs(tx,ty);}
}
void solve()
{cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>mp[i][j];for(int i=1;i<=n;i++) if(mp[i][1] == 1) dfs(i,1);for(int i=1;i<=n;i++) if(mp[i][m] == 1) dfs(i,m);for(int i=1;i<=m;i++) if(mp[1][i] == 1) dfs(1,i);for(int i=1;i<=m;i++) if(mp[n][i] == 1) dfs(n,i);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(mp[i][j] == 1)ans++;cout<<ans<<endl;
}signed main()
{IOSint T=1;pre_handle();
//	cin>>T;while(T--) solve(); return 0;
} 

沉沒孤島

題目鏈接:沉沒孤島

這道題和上一道題的思路是完全反過來即可,因為要讓所有的孤島沉沒,所以就需要找出哪些是孤島哪些不是孤島,上一題中的代碼已經將二者區分出來了,這道題我們只需要將標記為孤島的陸地作為海洋輸出即可,而非孤島的陸地可以用其他的數字區分出來,如果用0的話就分不清是海洋還是陸地了,如果用1的話就分不清是否為孤島了。

//https://kamacoder.com/problempage.php?pid=1174
//沉沒孤島
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define pii pair<int,int>
#define fi first
#define se second
const int N = 55;
vector<vector<int>> mp(N,vector<int>(N));
// vector<vector<bool>> v(N,vector<bool>(N));
int n,m,ans=0;
void pre_handle()
{}
int dis[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};void dfs(int x,int y)
{mp[x][y] = 2;for(int i=0;i<4;i++){int tx = x + dis[i][0];int ty = y + dis[i][1];if(tx < 1 || tx > n || ty < 1 || ty > m) continue;if(mp[tx][ty] == 1) dfs(tx,ty);}
}
void solve()
{cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>mp[i][j];for(int i=1;i<=n;i++) if(mp[i][1] == 1) dfs(i,1);for(int i=1;i<=n;i++) if(mp[i][m] == 1) dfs(i,m);for(int i=1;i<=m;i++) if(mp[1][i] == 1) dfs(1,i);for(int i=1;i<=m;i++) if(mp[n][i] == 1) dfs(n,i);// for(int i=1;i<=n;i++)// for(int j=1;j<=m;j++)// if(mp[i][j] == 1) v[i][j] = 1;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(mp[i][j] == 2) cout<<1<<' ';else cout<<0<<' ';}cout<<endl;}
}signed main()
{IOSint T=1;pre_handle();
//	cin>>T;while(T--) solve(); return 0;
} 

水流問題

題目鏈接:水流問題

這道題正向思維是遍歷每一個點然后去搜索他附近的比他低的點,但是這樣時間復雜度是很高的,所以我們可以借助逆向思維,因為他要求必須既能流到第一邊界又能流到第二邊界,所以我們可以從兩個邊界開始搜索比他高的位置,然后將所有的相鄰的比他高的位置都給標記出來,這個操作可以用兩個bool類型的數組來完成,最后只需要遍歷每個點,如果這個點被兩個標記數組給標記可達了,那么這個點就是所求的點,直接輸出即可,思路很簡單,但是實現起來較有難度。

//https://kamacoder.com/problempage.php?pid=1175
//水流問題
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define pii pair<int,int>
#define fi first
#define se second
const int N = 105;
vector<vector<int>> mp(N,vector<int>(N));
vector<vector<bool>> v1(N,vector<bool>(N,0)),v2(N,vector<bool>(N,0));
int n,m,ans=0;
void pre_handle()
{}
int dis[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};void dfs1(int x,int y)
{if(v1[x][y]) return ;v1[x][y] = true;for(int i=0;i<4;i++){int tx = x + dis[i][0];int ty = y + dis[i][1];if(tx < 1 || ty < 1 || tx > n || ty > m) continue;if(v1[tx][ty] == false && mp[tx][ty] >= mp[x][y]) dfs1(tx,ty);}
}
void dfs2(int x,int y)
{if(v2[x][y]) return ;v2[x][y] = true;for(int i=0;i<4;i++){int tx = x + dis[i][0];int ty = y + dis[i][1];if(tx < 1 || ty < 1 || tx > n || ty > m) continue;if(v2[tx][ty] == false && mp[tx][ty] >= mp[x][y]) dfs2(tx,ty);}
}
void solve()
{cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>mp[i][j];for(int i=1;i<=n;i++) dfs1(i,1);//"1"for(int i=1;i<=n;i++) dfs2(i,m);//"2"for(int i=1;i<=m;i++) dfs1(1,i);//"1"for(int i=1;i<=m;i++) dfs2(n,i);//"2"for(int i=1;i<=n;i++){for(int j=1;j<=m;j++)if(v1[i][j] && v2[i][j])cout<<i-1<<' '<<j-1<<endl;}
}signed main()
{IOSint T=1;pre_handle();
//	cin>>T;while(T--) solve(); return 0;
} 

建造最大島嶼

題目鏈接:建造最大島嶼

這道題是相對復雜的一道題了,想了很久的優化方法,后來看了題解,感覺又長腦子了,其實不需要對每一個點都去搜索,我們可以在一開始就先用普通的搜索方式將每一個島嶼都編號統一起來,編號要直接賦值地圖上然后將對應的編號的島嶼的面積映射關系存起來,然后在遍歷每一個為海洋的點的時候只需要看他的上下左右四個方向是否是島嶼然后將面積加起來即可,注意以下兩個坑:

1.可能全部都是陸地,這時候就需要將存面積的數組中的值作為答案了

2.要注意海洋點的四個方向有可能存在相同編號的陸地,所以需要在對四個方向分析的時候用一個bool數組存起來作為訪問標記,防止重復訪問累加面積

代碼實現起來極為惡心。?

//https://kamacoder.com/problempage.php?pid=1176
//建造最大島嶼
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define pii pair<int,int>
#define fi first
#define se second
const int N = 55;
int s=0;
vector<vector<int>> mp(N,vector<int>(N));
unordered_map<int,int> f;
int n,m,ans=0;
void pre_handle()
{}
int dis[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};void dfs(int x,int y,int mark)
{s++;mp[x][y] = mark;for(int i=0;i<4;i++){int tx = x + dis[i][0];int ty = y + dis[i][1];if(tx < 1 || tx > n || ty < 1 || ty > m) continue;if(mp[tx][ty] == 1) dfs(tx,ty,mark);}
}
void solve()
{cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>mp[i][j];int index=2;//島嶼的編號、面積for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(mp[i][j] == 1){s=0;dfs(i,j,index);f[index++] = s;}}}int ans=0;for(auto i : f) ans = max(ans,i.se);//防止沒有0的情況 !!!for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(mp[i][j] == 0){unordered_map<int,bool> v;int t=1;if(mp[i-1][j] && !v[mp[i-1][j]]){t+=f[mp[i-1][j]];v[mp[i-1][j]] = true;}if(mp[i+1][j] && !v[mp[i+1][j]]){t+=f[mp[i+1][j]];v[mp[i+1][j]] = true;}if(mp[i][j-1] && !v[mp[i][j-1]]){t+=f[mp[i][j-1]];v[mp[i][j-1]] = true;}if(mp[i][j+1] && !v[mp[i][j+1]]){t+=f[mp[i][j+1]];v[mp[i][j+1]] = true;}ans = max(ans,t);}}}cout<<ans<<endl;
}signed main()
{IOSint T=1;pre_handle();
//	cin>>T;while(T--) solve(); return 0;
} 

島嶼的周長

這道題其實不是一道搜索題,直接遍歷一遍將每個陸地點的上下左右四個方向的情況做一個判斷即可,但是需要注意的是,周長需要++的情況就是1.該點作為陸地邊界 2.該點作為地圖邊界,其實歸根結底,都是遇到邊界上的陸地就周長++,所以用1為初始的下標索引可以更簡便的統計周長,因為不管是哪一種邊界,都不會導致數組越界而且都是0。

//https://kamacoder.com/problempage.php?pid=1178
//島嶼的周長
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define pii pair<int,int>
#define fi first
#define se second
const int N = 55;
vector<vector<int>> mp(N,vector<int>(N));
int n,m,ans;
void pre_handle()
{}
int dis[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};void dfs(int x,int y)
{}
void solve()
{cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>mp[i][j];for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(mp[i][j] == 1){if(mp[i-1][j] == 0) ans++;if(mp[i+1][j] == 0) ans++;if(mp[i][j+1] == 0) ans++;if(mp[i][j-1] == 0) ans++;}}}cout<<ans<<endl;
}signed main()
{IOSint T=1;pre_handle();
//	cin>>T;while(T--) solve(); return 0;
} 

字符串接龍?

題目鏈接:字符串接龍

這是一道結合了建圖以及最短路的題,一般無權圖求最短路直接用搜索即可,這道題用BFS即可

這道題有兩個難點:怎么建圖,怎么求最短路?

建圖的還就需要對每個字符串進行枚舉所有可能變成的字符串,如果在字典中出現了,就說明這兩個字符串之間是可達的,可達的情況下就去判斷是否已經搜索過這個點了(因為BFS要求一個點只能搜一遍),在沒有搜索過的條件下再加入隊列開始搜索。

整體思路如下:

用一個set來儲存字典中的單詞(因為元素是string類型,而相對map來說內存更小)是只讀判斷存在狀態的最佳容器。

然后用一個map存放每個單詞以及映射的路徑長度(和普通的BFS一樣 只不過普通的BFS在兩個數組中存放了當前位置的路徑長度以及訪問狀態,這是string類型,只能利用map的映射關系來實現既能對是否訪問的判斷又能儲存路徑長度)

最后就是枚舉了,從BFS開始的隊首元素開始不斷的枚舉所有的能變成的字典中的元素,第一次達到就直接入隊進行搜索即可。

#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define pii pair<int,int>
#define fi first
#define se secondvoid pre_handle()
{} void solve()
{int n;cin>>n;string s1,s2;cin>>s1>>s2;unordered_set<string> st;//字符串字典unordered_map<string,int> mp;//用于存放從起始字符串到當前的最短距離(通過BFS計算)//同時還可以記錄該字符串是否被訪問過了for(int i=1;i<=n;i++){string x;cin>>x;st.insert(x);}queue<string> q;q.push(s1);mp[s1] = 1;while(!q.empty())//BFS{string now = q.front();q.pop();int step = mp[now];for(int i=0;i<now.size();i++){string t = now;for(int j=0;j<26;j++)//遍歷每一種情況 如果在字典中出現就說明可以連起來{t[i] = 'a' + j;if(t == s2){cout<<mp[now] + 1;return ;}//可以連起來的話就可以進行搜索了,但是BFS的前提是每個點只訪問一次 所以當前字符串必須是首次出現if(st.find(t) != st.end() && mp.find(t) == mp.end()){q.push(t);mp[t] = step + 1;}}}}cout<<0<<endl;
}signed main()
{IOSint T=1;pre_handle();
//	cin>>T;while(T--) solve(); return 0;
} 

有向圖的完全聯通?

點少邊多:鄰接矩陣

點多邊少:鄰接表

這道題是有向圖的入門題目

首先需要將圖建立起來,然后用dfs去遍歷所有可達點即可,如果能遍歷到所有點就是1否則就是-1

注意圖的遍歷的話需要有遞歸終止條件,每個點必須值訪問異一次,防止死循環。

#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define pii pair<int,int>
#define fi first
#define se second
const int N = 1e2+10;
vector<int> e[N];
vector<bool> v(N,0);
void pre_handle()
{} 
void dfs(int x)
{if(v[x] == true) return ;//防止重復訪問v[x] = true;//存的都是可達點 所以無需判斷for(auto i : e[x]) dfs(i);    
}
void solve()
{int n,m;cin>>n>>m;for(int i=1;i<=m;i++){int u,v;cin>>u>>v;e[u].push_back(v);}dfs(1);for(int i=1;i<=n;i++){if(v[i] == false){cout<<"-1"<<endl;return ;}}cout<<"1"<<endl;
}signed main()
{IOSint T=1;pre_handle();
//	cin>>T;while(T--) solve(); return 0;
} 

最后注意使用BFS(廣度優先搜索的時候元素一旦入隊就將其標記為已訪問)

期待后續的并查集和迪杰斯特拉算法吧~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92885.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92885.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92885.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AI驅動攻防升級,API安全走到關鍵檔口

在數字化轉型與AI技術快速發展的雙重驅動下&#xff0c;API已成為企業業務與外部世界連接的神經中樞。然而&#xff0c;隨著API的深度應用&#xff0c;針對API的攻擊規模與復雜性也在持續升級。 API為何頻頻成為黑客重點盯防的突破口&#xff1f;企業常見的API防護手段是否還能…

網絡基礎DAY18-動態路由協議基礎

動態路由協議基礎知識回顧&#xff1a;1.什么是路由&#xff1f; 答&#xff1a;是三層設備轉發IP報文的路徑信息。 2.路由有哪些來源&#xff1f; 答&#xff1a;1.直連路由2.靜態路由3.動態路由 3.有直連路由的條件&#xff1f; 答&#xff1a;1.二層和三層物理接口狀態為UP …

axios統一封裝規范管理

新建/api/ 1.新建統一處理文件/api/axios.ts import axios from "axios"const http axios.create({baseURL: import.meta.env.VITE_API_BASE_URL, // 從環境變量讀取timeout: 10000, });// 請求攔截器&#xff08;如添加 Token&#xff09; http.interceptors.reque…

Java學習第七十四部分——Elasticsearch(ES)

目錄 一、前言提要 二、核心特性 三、應用場景 四、主要優勢 五、集成方式 六、基礎操作 七、高級特性 八、概念類比——與關系型數據庫 九、簡單示例——實現存儲與搜索 十、生態集成——基于Spring Data Elasticsearch 十一、性能優化建議 十二、總結歸納概述 一…

TDengine 轉化函數 TO_UNIXTIMESTAMP 用戶手冊

TDengine TO_UNIXTIMESTAMP 函數用戶使用手冊 函數概述 TO_UNIXTIMESTAMP 是 TDengine 中的標量函數&#xff0c;用于將符合 ISO8601/RFC3339 標準的日期時間字符串轉換為 Unix 時間戳。與 TO_TIMESTAMP 不同&#xff0c;該函數專門處理標準格式的時間字符串&#xff0c;無需指…

Java 中的排序算法詳解

目錄 一、冒泡排序&#xff08;Bubble Sort&#xff09; 原理? 二、選擇排序&#xff08;Selection Sort&#xff09; 原理? 三、插入排序&#xff08;Insertion Sort&#xff09; 原理? 四、快速排序&#xff08;Quick Sort&#xff09; 原理? 五、歸并排序&…

Gitee如何成為國內企業DevOps轉型的首選平臺?

Gitee如何成為國內企業DevOps轉型的首選平臺&#xff1f; 在數字化轉型浪潮中&#xff0c;DevOps已成為提升企業研發效能的關鍵引擎。作為國內領先的代碼托管與協作平臺&#xff0c;Gitee憑借本土化優勢與全流程支持能力&#xff0c;正成為越來越多企業DevOps實踐的核心載體。本…

?Excel——SUMPRODUCT 函數

SUMPRODUCT 是 Excel 中最強大的函數之一&#xff0c;可以用于 ?多條件求和、加權計算、數組運算? 等復雜場景。下面通過 ?基礎語法 實用案例? 徹底講透它的用法&#xff01;?一、基礎語法?SUMPRODUCT(數組1, [數組2], [數組3], ...)?功能?&#xff1a;將多個數組的對…

告別虛函數性能焦慮:深入剖析C++多態的現代設計模式

?? 引言:當多態遇上性能瓶頸 我經常被問到這樣一個問題:“既然virtual函數這么方便,為什么在一些高性能場景下,大家卻避之不及?” 答案很簡單:性能。 在我參與的多個HPC項目和游戲引擎開發中,virtual函數調用往往成為性能分析工具中最顯眼的那個紅點。一個看似無害…

k8s-MongoDB 副本集部署

前提準備一套 k8s 集群worker 節點上的 /nfs/data 目錄掛載到磁盤一、NFS 高可用方案&#xff08;NFSkeepalivedSersync&#xff09;本方案 NFS 的高可用方案&#xff0c;應用服務器為 Client &#xff0c;兩臺文件服務器分別 Master 和 Slave&#xff0c;使用 keepalived 生成…

BI 系統數據看板全解析:讓數據可視化驅動業務決策

BI 系統數據看板全解析&#xff1a;讓數據可視化驅動業務決策在 BI 系統中&#xff0c;數據看板是連接原始數據與業務洞察的 “橋梁”。它將零散的業務指標轉化為直觀的可視化圖表&#xff0c;讓產品經理、運營人員等角色能快速把握業務動態。一個設計精良的數據看板&#xff0…

圖機器學習(14)——社交網絡分析

圖機器學習&#xff08;14&#xff09;——社交網絡分析0. 前言1. 數據集分析1.1 數據集介紹1.2 使用 networkx 加載數據集2. 網絡拓撲和社區檢測2.1 網絡拓撲2.2 社區檢測0. 前言 社交網站的崛起是近年來數字媒體領域最活躍的發展趨勢之一&#xff0c;數字社交互動已經融入人…

深入解析Hadoop MapReduce中Reduce階段排序的必要性

MapReduce概述與Reduce階段簡介MapReduce作為Hadoop生態系統的核心計算框架&#xff0c;其設計思想源自Google論文&#xff0c;通過"分而治之"的理念實現海量數據的并行處理。該模型將計算過程抽象為兩個關鍵階段&#xff1a;Map階段負責數據分解和初步處理&#xff…

7月23日華為機考真題第二題-200分

?? 點擊直達筆試專欄 ??《大廠筆試突圍》 ?? 春秋招筆試突圍在線OJ ?? 筆試突圍OJ bishipass.com 02. 圖書館資源分配系統 問題描述 A先生是一位圖書館管理員,負責管理圖書采購和分配工作。圖書館收到了來自不同出版社的圖書批次,同時有多位讀者代表排隊申請圖書…

基于深度學習的圖像分類:使用ResNet實現高效分類

最近研學過程中發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊鏈接跳轉到網站人工智能及編程語言學習教程。讀者們可以通過里面的文章詳細了解一下人工智能及其編程等教程和學習方法。下面開始對正文內容的…

JVM:工具

JVMjpsjstatjmapjhatjstackjconsolejvisualvmjps jps&#xff08; Java Virtual Machine Process Status Tool &#xff09;&#xff0c;是 JDK 中的一個命令行工具&#xff0c;用于列出當前正在運行的 JVM 實例的信息。其對于監控和管理運行在多個 JVM 上的 Java 應用程序特別…

Elasticsearch Circuit Breaker 全面解析與最佳實踐

一、Circuit Breaker 簡介 Elasticsearch 是基于 JVM 的搜索引擎&#xff0c;其內存管理十分重要。為了避免單個操作或查詢耗費過多內存導致節點不可用&#xff0c;Elasticsearch 引入了 Circuit Breaker&#xff08;熔斷器&#xff09;機制。當內存使用達到熔斷器預設閾值時&a…

ARM-定時器-定時器函數封裝配置

以TIMER7為例&#xff0c;對定時器函數進行封裝注意事項&#xff1a;GD32中TIMER7是高級定時器&#xff0c;相關詳細請參考上一篇文章。main.c//main.c#include "gd32f4xx.h" #include "systick.h" #include <stdio.h> #include "main.h" …

【日志】unity俄羅斯方塊——邊界限制檢測

Bug修復記錄 項目場景 嘗試使用Unity獨自制作俄羅斯方塊&#xff08;也許很沒有必要&#xff0c;網上隨便一搜就有教程&#xff09; 問題描述 俄羅斯方塊的邊緣檢測出錯了&#xff0c;對方塊進行旋轉后&#xff0c;無法到達最左側或者最下側的位置&#xff0c;以及其他問題。演…

C++ string:準 STL Container

歷史STL 最初是一套獨立的泛型庫&#xff08;Alexander Stepanov 等人貢獻&#xff09;&#xff0c;后來被吸納進 C 標準庫&#xff1b;std::basic_string 則是早期 C 標準&#xff08;Cfront / ARM 時代&#xff09;就存在的“字符串類”&#xff0c;并非 STL 原生物。std::st…