搜索(DFS BFS)专题练习

时间:2022-07-24
本文章向大家介绍搜索(DFS BFS)专题练习,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

好长时间没有做搜索的题目了,今天做题遇见一个有点生疏,就做一个专题训练熟悉一下。

NC14572 走出迷宫

题意:很简单的问题,就是一个地图,上面S是入口,然后E是出口。#代表陷阱不能走,问我们是否能够走出迷宫。

思路:这跟显然是一个DFS的最基础的题目。我们可以用一个二维字符数组进行存图,然后我们可以先找到入口的位置,我们需要一个vis数组来表示当前节点是否被访问过。如此一来我们就可以就可以用DFS(不撞南墙不回头式搜索了) 。

#include<bits/stdc++.h>
#define maxn 505
using namespace std;
int n,m;
int x,y;
char ma[maxn][maxn];
int dx[5] = {0,0,-1,0,1};//方向数组
int dy[5] = {0,-1,0,1,0};
bool flag= 0;
bool vis[maxn][maxn];

void dfs(int x,int y){
    if(ma[x][y]=='E'){//找到我们就return;
        cout<<"Yes"<<endl; 
        flag = 1;
        return ;
    }
    for(int i=1;i<=4;i++){//往四个方向搜索
        int xx = x + dx[i];
        int yy = y + dy[i];
        if(xx < 1 || xx >n || yy <1 || yy > m || vis[xx][yy] || ma[xx][yy]=='#'){//约束条件
            continue;
        }
        vis[xx][yy] = 1;//标记
        dfs(xx,yy);//接着搜索
    }
}

int main(){
    while(cin>>n>>m){
        flag = 0;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>ma[i][j];
                if(ma[i][j]=='S') {
                    x = i;
                    y = j;
                }
            }
        }
        vis[x][y] = 1;
        dfs(x,y);
        if(!flag) cout<<"No"<<endl;
    }
    return 0;
}

NC15291 幸运数字Ⅱ

题意: 题目描述 定义一个数字为幸运数字当且仅当它的所有数位都是4或者7。 比如说,47、744、4都是幸运数字而5、17、467都不是。 定义next(x)为大于等于x的第一个幸运数字。给定l,r,请求出next(l) + next(l + 1) + … + next(r - 1) + next®。

输入描述: 两个整数l和r (1 <= l <= r <= 1000,000,000)。

输出描述: 一个数字表示答案。

思路:这是一个非常有意思的题目,我们一拿到这个题想的肯定是我们如何把幸运数字给搞出来。然后我们才能看【l,r】具体是在哪几个幸运数字之间的。那么我们可以用DFS进行打表,然后我们对其进行排序,之后我们可以算出两个端点的所处幸运数字的位置,之后就是看区间可以分为多少段,每一个段的幸运数字是一样的,如此我们就可以得到答案了。

#include<bits/stdc++.h>
using namespace std;
long long a[10005];
long long cnt=2;
void dfs(long long x)
{

	if(x>1e10)
	return;
	if(x>10)
	a[cnt++]=x;
    
	dfs(x*10+4);
	dfs(x*10+7);
}
int main(){
	long long l,r;
	long long sum=0;
	cin>>l>>r;
	a[0]=4;
	a[1]=7;
	dfs(4);
	dfs(7);
	sort(a,a+cnt+1);
	long long p,k;
	p=lower_bound(a,a+cnt+1,l)-a;
	k=lower_bound(a,a+cnt+1,r)-a;
    
	for(long long i=p;i<=k;i++){
		sum=sum+(min(a[i],r)-l+1)*a[i];
		l=a[i]+1;
	}
	printf("%lldn",sum);
	return 0;
}

NC14698 模拟战役

题意:这个题目也是非常有意思的,那么首先我们来看这场战争的规则,就是双方每次动用一枚大炮,炮击对面有视野的大炮,然后以攻击点3*3的中心区域如果有大炮那么会产生连锁反应,会继续爆炸。那么我们开挂了,所以能看到对面所有的大炮的部署情况。那么现在给出我们跟电脑的大炮部署地图,在我们选择最优的情况,在摧毁对面所有的大炮的情况下,我们还能保留几门大炮。

思路:那么我们很容易想到这是一个联通块问题,那么联通块问题可以用什么呢?并查集!对,但是我们这个专题是关于DFS的,所以我们得用DFS来解决联通块问题。我们该如何搜索呢?每次找到一门大炮,那么我们就可以对其四周进行搜索,然后记录这个联通块里面有多少门大炮,然后如果我们的联通块的数量是少于电脑的,那么我们肯定输啊。直接输出-1,但如果我们的联通块的数量是大于电脑的,那么我们肯定要贪心的想每次选出联通块中数量最少的大炮这个联通块然后打对面。如此一来我们最终能够保留最多数量的大炮

#include<bits/stdc++.h>
using namespace std;
char mp[10][105];
int m;
int ans1[405],ans2[405];
int num;
int to[][2]={1,0,-1,0,0,1,0,-1,-1,-1,-1,1,1,-1,1,1};
void dfs(int x,int y,int k){
    if(mp[x][y]=='.')  return ;
    mp[x][y]='.',++num;
    for(int i=0;i<8;i++){
        int fx=x+to[i][0],fy=y+to[i][1];
        if(fx>=0+k&&fx<4+k&&fy>=0&&fy<m){
            dfs(fx,fy,k);
        }
    }
}
int main(){
    cin>>m;
    for(int i=0;i<8;i++) cin>>mp[i];
    for(int i=0;i<4;i++){
        for(int j=0;j<m;j++){
            if(mp[i][j]=='*'){
                num=0;
                dfs(i,j,0);
                ans1[++ans1[0]]=num;
            }
        }
    }
 
    for(int i=4;i<8;i++){
        for(int j=0;j<m;j++){
            if(mp[i][j]=='*'){
                num=0;
                dfs(i,j,4);
                ans2[++ans2[0]]=num;
            }
        }
    }
    if(ans1[0]>ans2[0]) cout<<-1;
    else{
        sort(ans2+1,ans2+ans2[0]+1);
        int ans=0;
        for(int i=ans1[0];i<=ans2[0];i++){
            ans+=ans2[i];
        }
        cout<<ans;
    }
    return 0;
}

这里还是给大家提供下并查集做法吧

#include<bits/stdc++.h>
using namespace std;
const int N=101;
char a[N][N];
int dx[8]={0,0,1,-1,1,-1,1,-1};
int dy[8]={1,-1,0,0,1,-1,-1,1};
int fa[N*N],siz[N*N],m,sav[N*N],e,t;
inline int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void merge(int x,int y){
    int a=find(x),b=find(y);
    if(a!=b){
        fa[a]=b,siz[b]+=siz[a];
    }
}
int main(){
    scanf("%d",&m);
    for(int i=1;i<=8;++i){
        for(int j=1;j<=m;++j){
            scanf(" %c",&a[i][j]);fa[(i-1)*m+j]=(i-1)*m+j,siz[(i-1)*m+j]=1;
        }
    }
    for(int i=1;i<=8;++i){
        for(int j=1;j<=m;++j){
            if(a[i][j]=='*'){
                for(int k=0;k<8;++k){
                    int x=i+dx[k],y=j+dy[k];
                    if(((i<=4&&x&&x<=4)||(i>4&&x>4&&x<=8))&&y&&y<=m){
                        if(a[x][y]=='*'){
                            merge((x-1)*m+y,(i-1)*m+j);
                        }
                    }
                }
            }
        }
    }
    for(int i=1;i<=8;++i){
        for(int j=1;j<=m;++j){
            if(a[i][j]=='*'&&fa[(i-1)*m+j]==(i-1)*m+j){
                if(i<=4){
                    ++t;
                }else{
                    sav[++e]=siz[(i-1)*m+j];
                }
            }
        }
    }
    if(e<t){
        puts("-1");
        return 0;
    }
    sort(sav+1,sav+e+1);
    int res=0;
    for(int i=t;i<=e;++i){
        res+=sav[i];
    }
    printf("%d",res);
    return 0;
}