搜索蓝桥备赛

题型一:Flood Fill

计算相连通区域块个数 都是判断是否有无被遍历过的条件下 开始进行搜索条件

池塘计数(相连通区域块的个数)

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N=1010;
const int M=N*N;
char g[N][N];
PII q[M];
bool st[N][N];
int n,m;
bool bfs(int sx,int sy){
    int hh=0,tt=0;
    q[0]={sx,sy};
    st[sx][sy]=true;
    while(hh<=tt){
        PII t=q[hh++];
        for(int i=t.x-1;i<=t.x+1;i++){
            for(int j=t.y-1;j<=t.y+1;j++){
                if(i==t.x&&j==t.y) continue;
                if(st[i][j]==true) continue;
                if(i<0||i>=n||j<0||j>=m) continue;
                if(g[i][j]=='.') continue;
                q[++tt]={i,j};
                st[i][j]=true;
            }
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++){
        cin>>g[i];
    }
    int cnt=0;
    memset(st,false,sizeof st);
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(g[i][j]=='W'&&st[i][j]==false){//必须确保此次遍历的W不是已经遍历过的联通块
                bfs(i,j);
                cnt++;
            }
        }
    }
    cout<<cnt<<endl;
    return 0;
}

城堡问题(区域块计数+记录最大区域块)

#include<bits/stdc++.h>

#define x first 
#define y second
using namespace std;

typedef pair<int,int> PII;
const int N=55;
const int M=N*N;

int n,m;
int g[N][N];
PII q[M];
bool st[N][N];

int bfs(int sx,int sy){
    int dx[]={0,-1,0,1};
    int dy[]={-1,0,1,0};
    int hh=0,tt=0;
    int area=0;
    q[0]={sx,sy};
    st[sx][sy]=true;
    while(hh<=tt){
        PII t=q[hh++];
        area++;//只要能取出 就面积加1
        for(int i=0;i<4;i++){
            int a=t.x+dx[i],b=t.y+dy[i];
            if(a<0||a>=n||b<0||b>=m) continue;
            if(st[a][b]) continue;
            if(g[a][b]>>i&1) continue;
            q[++tt]={a,b};
            st[a][b]=true;
        }
    }
    return area;
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>g[i][j];
        }
    }
    int cnt=0,area=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(!st[i][j]){
                area=max(area,bfs(i,j));
                cnt++;
            }
        }
    }
    cout<<cnt<<endl;
    cout<<area<<endl;
    return 0;
}

题型二:最短路模型 

bfs一层一层的遍历 最早到达终点的一定是最短的

dist[a][b]=dist[t.x][t.y]+1; 

献给阿尔吉侬的花束

//这种仅仅是判断连通性 是否可以抵达并不可以最短路
//最短路采取dist数组更新 或者dfs
#include<bits/stdc++.h>
#define x first 
#define y second 
using namespace std;
typedef pair<int,int>PII;
const int N=210;
const int M=N*N;
int n,m;
char g[N][N];
int dist[N][N];
PII q[M];

int bfs(int sx,int sy){
    int hh=0,tt=0;
    q[0]={sx,sy};
    int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
    memset(dist,-1,sizeof dist);
    dist[sx][sy]=0;
    while(hh<=tt){
        PII t=q[hh++];
        for(int i=0;i<4;i++){
            int a=t.x+dx[i],b=t.y+dy[i];
            if(a<0||a>=n||b<0||b>=m) continue;
            if (g[a][b]=='#') continue;  
            if(dist[a][b]!=-1) continue;
            if(g[a][b]=='E') return dist[t.x][t.y]+1;
            dist[a][b]=dist[t.x][t.y]+1;
            q[++tt]={a,b};
        }
    }
    return -1;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        cin>>n>>m;
        for(int i=0;i<n;i++) cin>>g[i];
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(g[i][j]=='S'){
                    if(bfs(i,j)!=-1){
                        cout<<bfs(i,j)<<endl;
                    }else{
                        cout<<"oop!"<<endl;
                    }
                }
            }
        }
    }
    return 0;
}

 武士风度的牛

#include<bits/stdc++.h>

#define x first 
#define y second
using namespace std;

typedef pair<int,int> PII;
const int N=155,M=N*N;

int n,m;
char g[N][N];
PII q[M];
int dist[N][N];

int bfs(){
    int dx[]={-2,-1,1,2,2,1,-1,-2};
    int dy[]={1,2,2,1,-1,-2,-2,-1};
    
    int sx,sy;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(g[i][j]=='K'){
                sx=i,sy=j;
            }
        }
    }
    int hh=0,tt=0;
    q[0]={sx,sy};
    memset(dist,-1,sizeof dist);
    dist[sx][sy]=0;
    while(hh<=tt){
        auto t=q[hh++];
        for(int i=0;i<8;i++){
            int a=t.x+dx[i],b=t.y+dy[i];
            if(a<0||a>=n||b<0||b>=m) continue;
            if(g[a][b]=='*') continue;
            if(dist[a][b]!=-1) continue;//是否被遍历过  如果不为-1 就代表已经放入队列中
            if(g[a][b]=='H') return dist[t.x][t.y]+1;
            
            dist[a][b]=dist[t.x][t.y]+1;
            q[++tt]={a,b};
        }
    }
    return -1;
}
int main(){
    cin>>m>>n;
    for(int i=0;i<n;i++) cin>>g[i];
    cout<<bfs()<<endl;
    return 0;
}

题型三:剪枝

dfs{

    if(现已经搜索的结果大于之前搜到的结果)  return;

    if(搜索物品条件(数目)已经达标)return;

    for(遍历每个物品){

         if(物体不满足最终主要条件) return;

         if(此物品已经满足条件) {

                物品进行标记;

                dfs;

                物品取消标记;

         }

    }

}

飞机降落

#include<bits/stdc++.h>
using namespace std;
int t,n,a[15][3];
bool st[15],flag;

void dfs(int k,int last){// 降落飞机数量 上一架飞机完成降落的时间
    if(k>=n){//已经全部降落
        puts("YES");
        flag=true;
    }
    if(flag){
        return;
    }
    for(int i=1;i<=n;i++){
        if(!st[i]){//还未降落
            if(a[i][1]<last) return;//最迟时间还未降落 就不满足
            st[i]=true;
            if(last<a[i][0]) dfs(k+1,a[i][0]+a[i][2]);//立马下降
            else dfs(k+1,last+a[i][2]);//无法立马下降
            st[i]=false;//否则无法下降
        }
    }
}
int main(){
    cin>>t;
    while(t--){
        cin>>n;
        memset(st,0,sizeof st);
        for(int i=1;i<=n;i++){
            cin>>a[i][0]>>a[i][1]>>a[i][2];
            a[i][1]+=a[i][0];//最迟降落时间
        }
        flag=false;
        dfs(0,0);
        if(!flag) puts("NO");
    }
    return 0;
}

小猫爬山

#include<bits/stdc++.h>
using namespace std;

const int N=20;
int cat[N],cab[N];
int n,w;
int ans;
bool cmp(int a,int b){
    return a>b;
}
void dfs(int now,int cnt){//小猫的数量 缆车的数量
    if(cnt>=ans){//如果已经超过最小的缆车数量 直接返回
        return;
    }
    if(now==n+1){//小猫的数量
        ans=min(ans,cnt);
        return;
    }
    //尝试分配到已经租用的缆车上
    for(int i=1;i<=cnt;i++){//分配到已经租用的缆车
        if(cab[i]+cat[now]<=w){
            cab[i]+=cat[now];
            dfs(now+1,cnt);
            cab[i]-=cat[now];//还原
        }
    }
    //新开一辆缆车
    cab[cnt+1]=cat[now];
    dfs(now+1,cnt+1);
    cab[cnt+1]=0;
}
int main(){
    cin>>n>>w;
    for(int i=1;i<=n;i++){
        cin>>cat[i];
    }
    sort(cat+1,cat+1+n,cmp);
    ans=n;
    dfs(1,0);
    cout<<ans<<endl;
    return 0;
}

题型四:DFS连通性(计数)

迷宫(判断是否连通)

#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n;
char g[N][N];
int xa,xb,ya,yb;
int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};
bool st[N][N];

bool dfs(int x,int y){
    if(x==xb&&y==yb) return true;
    st[x][y]=true;
    for(int i=0;i<4;i++){
        int a=x+dx[i],b=y+dy[i];
        if(a<0||a>=n||b<0||b>=n) continue;
        if(st[a][b]) continue;
        if(g[a][b]=='#') continue;
        if(dfs(a,b)) return true;
    }
    return false;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=0;i<n;i++) cin>>g[i];
        cin>>xa>>ya>>xb>>yb;
        memset(st,0,sizeof st);
        if(g[xa][ya]=='#'||g[xb][yb]=='#'){
            cout<<"NO"<<endl;
        }else{
            if(dfs(xa,ya)) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
    }
    return 0;
}

红与黑(dfs联通块内计数)

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 25;

int n, m;
char g[N][N];
bool st[N][N];

int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int dfs(int x, int y)
{
    int cnt = 1;

    st[x][y] = true;
    for (int i = 0; i < 4; i ++ )
    {
        int a = x + dx[i], b = y + dy[i];
        if (a < 0 || a >= n || b < 0 || b >= m) continue;
        if (g[a][b] != '.') continue;
        if (st[a][b]) continue;

        cnt += dfs(a, b);//从最终一步一步返回dfs(a,b)=1, cnt+=dfs(a,b)
    }

    return cnt;
}

int main()
{
    while (cin >> m >> n, n || m)
    {
        for (int i = 0; i < n; i ++ ) cin >> g[i];

        int x, y;
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                if (g[i][j] == '@')
                {
                    x = i;
                    y = j;
                }

        memset(st, 0, sizeof st);
        cout << dfs(x, y) << endl;
    }

    return 0;
}

马走日(bfs联通块计数)

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int M=1000;
typedef pair<int,int>PII;
PII q[M];
const int N=1010;
int n,m,x,y;
bool d[N][N];
int dx[]={-2,-2,-1,-1,1,1,2,2};
int dy[]={1,-1,2,-2,2,-2,1,-1};
int bfs(int sx,int sy){
    int cnt=0;
    int hh=0,tt=0;
    q[0]={sx,sy};
    d[x][y]=true;
    while(hh<=tt){
        PII t=q[hh++];
        for(int i=0;i<8;i++){
            int a=x+dx[i],b=y+dy[i];
            if(a<0||a>=n||b<0||b>=m) continue;
            if(d[x][y]!=false) continue;
            cnt++;
            if(a==x&&b==y){
                return cnt;
            }
            d[a][b]=true;
            q[++tt]={a,b};
        }
    }
}

int main(){
    cin>>n>>m;
    cin>>x>>y;
    memset(d,false,sizeof d);
    cout<<bfs(x,y);
    return 0;
}

全球变暖(联通块内加条件)

#include<bits/stdc++.h>
using namespace std;

int n;
char a[1010][1010]; //地图
int vis[1010][1010]={0};  //标记是否搜过
int d[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}}; //四个方向
int flag;  //用于标记这个岛中是否被完全淹没
void dfs(int x, int y){
    vis[x][y] = 1;      //标记这个'#'被搜过。注意为什么可以放在这里
    if(a[x][y+1]=='#' && a[x][y-1]=='#' && a[x+1][y]=='#' && a[x-1][y]=='#')
        flag = 1;       //上下左右都是陆地,不会淹没
    for(int i = 0; i < 4; i++){ //继续DFS周围的陆地
        int nx = x + d[i][0], ny = y + d[i][1];
      //if(nx>=1 && nx<=n && ny>=1 && ny<=n && vis[nx][ny]==0 && a[nx][ny]=='#') //题目说边上都是水,所以不用这么写了
        if(vis[nx][ny]==0 && a[nx][ny]=='#') //继续DFS未搜过的陆地,目的是标记它们
            dfs(nx,ny);
    }
}

int main(){
    cin >> n;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            cin >> a[i][j];
    int ans = 0 ;
    for(int i = 1; i <= n; i++)  //DFS所有像素点
        for(int j = 1; j <= n; j++)
            if(a[i][j]=='#' && vis[i][j]==0){
                flag = 0;
                dfs(i,j);
                if(flag == 0)  //这个岛全部被淹
                    ans++;     //统计岛的数量
            }
    cout<<ans<<endl;
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
int n;
char a[1010][1010];
bool st[1010][1010];
int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};
int flag;
void dfs(int x,int y){
    st[x][y]=true;
    if(a[x][y+1]=='#'&&a[x][y-1]=='#'&&a[x+1][y]=='#'&&a[x-1][y]=='#') flag=1;//上下都是陆地不会被淹没
    for(int i=0;i<n;i++){
        int ax=x+dx[i],by=y+dy[i];
        if(st[ax][by]==true) continue;
        if(ax<=0||ax>n||by<=0||by>0) continue;
        if(a[ax][by]=='#') dfs(ax,by);
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>a[i][j];
        }
    }
    memset(st,false,sizeof st);
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(a[i][j]=='#'&&st[i][j]==false){
                flag=0;
                dfs(i,j);
                if(flag==0){//这个岛全部被淹
                    ans++;
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

功夫传人(bfs)

#include<bits/stdc++.h>
using namespace std;
int big[110000],d[110000];
vector<int> p[110000];
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n;
    double z,r,sum=0.0;
    cin>>n>>z>>r;//师门总人数 祖师爷功力值 折扣百分比值
    r=(1-r/100.0);//功力逐渐递减
    for(int i=0;i<n;i++){
        int k,x;
        cin>>k;
        if(!k){//得道者
            cin>>x;
            big[i]=x;//i号功力被放大x倍
        }
        for(int j=0;j<k;j++){
            cin>>x;
            p[i].push_back(x);//i人的子弟
        }
    }
    int t;
    queue<int> q;
    q.push(0);//祖师爷是根节点
    d[0]=0;
    while(!q.empty()){
        t=q.front();
        q.pop();
        for(int i=0;i<p[t].size();i++){
            d[p[t][i]]=d[t]+1;//代数增加 所以功力逐渐减少 (树的层数)
            if(big[p[t][i]]){//得道者
                sum+=z*pow(r,d[p[t][i]])*big[p[t][i]];
            }else{
                q.push(p[t][i]);
            }
        }
    }
    if(n==1&&big[0]) sum=z*big[0];
    cout<<(int)sum<<endl;
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值