一.BFS广搜:
原理:
使用队列queue先进先出的特点计算最短路等等
模板:
BFS算法:
初始化队列Q;
Q = {起点};
标记s;
while(Q非空)
{
取Q队首元素u;
u出队;
if(u==目标状态)
{
……
}
else
{
所有与u相邻且未被访问的点进入队列;
标记u为已访问;
}
}
例题:
Flood fill 模型
二.多源BFS
原理:
由假设点0开始,把多个源点放入队列中,开始bfs,(求曼哈顿距离的题)相当于逆向求解;
例题:曼哈顿距离题
代码:
#include <bits/stdc++.h>
using namespace std;
#define PII pair<int ,int >
const int N=1010;
char g[N][N];
int n,m,dis[N][N];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
queue<PII>q;
void bfs(){
memset(dis,-1,sizeof dis);
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
if(g[i][j]=='1'){
q.push({i,j});
dis[i][j]=0;
}
}
}
while (q.size()){
auto t=q.front();
q.pop();
for (int i = 0; i <4 ; ++i) {
int xx=t.first+dx[i],yy=t.second+dy[i];
if(xx<1||xx>n||yy<1||yy>m)continue;
if(dis[xx][yy]!=-1)continue;
q.push({xx,yy});
dis[xx][yy]=dis[t.first][t.second]+1;
}
}
}
int main(){
cin>>n>>m;
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
cin>>g[i][j];
}
}
bfs();
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
cout<<dis[i][j]<<' ';
}
cout<<endl;
}```cpp
#include <bits/stdc++.h>
using namespace std;
int fa[1005], n, m;
struct node{
int a;
int b;
int t;
}u[100005];;
bool cmp(node fir,node sec)
{
return fir.t<sec.t;
}
int find(int x){
if(x!=fa[x])fa[x]=find(fa[x]);
return fa[x];
}
void unity(int x, int y)
{
int r1 = find(x);//找到x的祖先
int r2 = find(y);//找到y的祖先
fa[r1] = r2;//祖先和祖先结为父子(谁是父亲谁是儿子都可以)
}//合并
bool check(){
int sum=0;
for (int i = 1; i <=n ; ++i) {
if(fa[i]==i)
sum++;
if(sum==2)
return 0;
}
return 1;
}
int main(){
cin>>n>>m;
for (int i = 1; i <=n ; ++i) {
fa[i]=i;
}
for (int i = 1; i <=m ; ++i) {
cin>>u[i].a>>u[i].b>>u[i].t;
}
sort(u+1,u+1+m,cmp);
for (int i = 1; i <=m ; ++i) {
unity(u[i].a,u[i].b);
if (check()){
cout<<u[i].t<<endl;
return 0;
}
}
cout<<"-1"<<endl;
}
三.并查集:
作用:
将两个集合合成一个集合,联通块的求解,查询节点的祖宗,合并集合
原理:
对于每个集合,我们使用一棵树来表示。树根的编号是整个集合的编号。 集合中每个结点存储它的父节点,fa[x]表示x的父节点。
步骤:
- 如何判断集合编号(树根):fa[x] == x
- 如何求x的集合编号:while(fa[x] != x) x= fa[x];
- 如何合并两个集合:假设a是第一个集合的编号,b是第二个集合的编号,则fa[a] = b;
示例:
并查集题目
P1111 修复公路
代码:
#include <bits/stdc++.h> using namespace std; int fa[1005], n, m; struct node{ int a; int b; int t; }u[100005]; bool cmp(node fir,node sec) { return fir.t<sec.t; } int find(int x){ if(x!=fa[x])fa[x]=find(fa[x]); return fa[x]; } void unity(int x, int y) { int r1 = find(x);//找到x的祖先 int r2 = find(y);//找到y的祖先 fa[r1] = r2;//祖先和祖先结为父子(谁是父亲谁是儿子都可以) }//合并 bool check(){ int sum=0; for (int i = 1; i <=n ; ++i) { if(fa[i]==i) sum++; if(sum==2) return 0; } return 1; } int main(){ cin>>n>>m; for (int i = 1; i <=n ; ++i) { fa[i]=i; } for (int i = 1; i <=m ; ++i) { cin>>u[i].a>>u[i].b>>u[i].t; } sort(u+1,u+1+m,cmp); for (int i = 1; i <=m ; ++i) { unity(u[i].a,u[i].b); if (check()){ cout<<u[i].t<<endl; return 0; } } cout<<"-1"<<endl; }