一.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的父节点。

步骤:

  1. 如何判断集合编号(树根):fa[x] == x
  2. 如何求x的集合编号:while(fa[x] != x) x= fa[x];
  3. 如何合并两个集合:假设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;
    }
posted on 2023-02-05 00:17  IR101  阅读(41)  评论(0编辑  收藏  举报  来源