三.搜索与图论(未完结)

DFS(深搜)

之前写过三篇关于dfs的

练习总结:

基础算法--递归搜索DFS练习总结(上)-CSDN博客

基础算法--递归搜索DFS练习总结(中)-CSDN博客

基础算法--递归搜索DFS练习总结(下)-CSDN博客

以下题目均为

补充练习: 

P1460 [USACO2.1] 健康的荷斯坦奶牛 Healthy Holsteins 

第一种暴力搜索dfs(超时未AC 90 points):

#include<iostream>
#include<cstring>
using namespace std;
int n,m,a[30],b[20][30],c[30],ans;
bool flag[20],key;
bool check(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++) if(flag[j]) c[i]+=b[j][i];
        if(a[i]>c[i]) return false;
    }
    return true;
}
void dfs(int x,int cnt){
    if(x==cnt+1){
        if(check()) {key=true;ans=cnt;}
        memset(c,0,sizeof c);
        return ;
    }
    for(int i=x;i<=m;i++){
        if(!flag[i]){
            flag[i]=true;
            dfs(x+1,cnt);
            if(key) return ;
            flag[i]=false;
        }
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    cin>>m;
    for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) cin>>b[i][j];
    for(int i=1;i<=m;i++){
        memset(flag,0,sizeof flag);
        memset(c,0,sizeof c);
        dfs(1,i);
        if(key){
            cout<<ans<<" ";
            for(int i=1;i<=m;i++) if(flag[i]) cout<<i<<" ";
            return 0;
        }
    }
}

第二种暴力搜索dfs(AC):

#include<iostream>
using namespace std;
int n,m,a[30],b[20][30],c[30],ans=1e9,res[30];
//数组c:每次搜索选的饲料编号,数组res:存储解
//判断每次选的那些饲料中的维生素之和是不是都大于等于牛需要的量 
bool check(int x){
    for(int i=1;i<=n;i++){
        int sum=0;
        for(int j=1;j<=x;j++) sum+=b[c[j]][i];
        if(sum<a[i]) return false;
    }
    return true;
}
void dfs(int curPos,int curCnt){
    if(curPos>m){//当前位置超过边界
        if(check(curCnt)){//必须使牛够吃
            if(curCnt<ans){//如果小于以前的最优解
                ans=curCnt;//更新答案
                for(int i=1;i<=m;i++) res[i]=c[i];//更新答案数组
            }
        }
        return ;
    }
    c[curCnt+1]=curPos;//把当前位置放在数组里
    dfs(curPos+1,curCnt+1);//搜索一步
    c[curCnt+1]=0;//回溯一步
    dfs(curPos+1,curCnt);//如果不选第curPos种饲料
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    cin>>m;
    for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) cin>>b[i][j];
    dfs(1,0);
    cout<<ans<<" ";
    for(int i=1;i<=ans;i++) cout<<res[i]<<" ";
    return 0;
}

P1451 求细胞数量

dfs(AC):

思路:不为0的地方就是细胞,然后dfs搜连通块,把搜到的都归0,保证不重复

#include<iostream>
using namespace std;
int n,m,ans;
char a[105][105];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
void dfs(int x,int y){
    if(x<0||y<0||x>=n||y>=m) return ;
    a[x][y]='0';
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(xx>=0&&xx<n&&yy>=0&&yy<m){
            if(a[xx][yy]!='0'){
                dfs(xx,yy);
            }
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++) {
        for(int j=0;j<m;j++) {
            if(a[i][j]!='0'){
                dfs(i,j);
                ans++;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

P1331 海战

dfs(AC):

和细胞一样的思路,唯一需要注意的是对于斜着连着的情况要特殊输出

#include<iostream>
using namespace std;
int n,m,ans;
char a[1005][1005];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
bool flag;
void dfs(int x,int y){
    if(flag) return ;
    if(x<0||y<0||x>=n||y>=m) return ;
    a[x][y]='.';
    if(a[x-1][y+1]=='#'&&a[x-1][y]=='.'&&a[x][y+1]=='.') {flag=true; return ;}
    if(a[x+1][y+1]=='#'&&a[x+1][y]=='.'&&a[x][y+1]=='.') {flag=true; return ;}
    if(a[x+1][y-1]=='#'&&a[x+1][y]=='.'&&a[x][y-1]=='.') {flag=true; return ;}
    if(a[x-1][y-1]=='#'&&a[x-1][y]=='.'&&a[x][y-1]=='.') {flag=true; return ;}
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(xx>=0&&xx<n&&yy>=0&&yy<m){
            if(a[xx][yy]!='.'){
                dfs(xx,yy);
            }
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++) {
        for(int j=0;j<m;j++) {
            if(a[i][j]!='.'){
                dfs(i,j);
                ans++;
            }
        }
    }
    if(!flag) cout<<"There are "<<ans<<" ships."<<endl;
    else cout<<"Bad placement."<<endl;
    return 0;
}

B3625 迷宫寻路

 dfs(AC):

#include<iostream>
using namespace std;
int n,m;
char a[105][105];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
void dfs(int x,int y){
    if(a[x-1][y]=='#'){
        if(a[x][y+1]=='#'){
            if(a[x+1][y]=='#'){
                if(a[x-1][y]=='#'){
                    return ;
                }
            }
        }
    }
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(xx>0&&xx<=n&&yy>0&&yy<=m&&a[xx][yy]=='.'){
            a[xx][yy]='#';
            dfs(xx,yy);
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=0;i<=m+1;i++) a[0][i]='#',a[n+1][i]='#';
    for(int i=1;i<=n;i++) a[i][0]='#',a[i][m+1]='#';
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];
    dfs(1,1);
    if(a[n][m]=='#') cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
    return 0;
}

 bfs(AC):

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
typedef pair<int,int> pii;
int n,m,d[105][105];
char a[105][105];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
int bfs(){
    queue<pii>q;
    q.push({0,0});
    memset(d,-1,sizeof d);
    d[0][0]=0;
    while(q.size()){
        auto t=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            int x=t.first+dx[i],y=t.second+dy[i];
            if(x>=0&&x<n&&y>=0&&y<m&&a[x][y]=='.'&&d[x][y]==-1){
                d[x][y]=d[t.first][t.second]+1;
                q.push({x,y});
            }
        }
    }
    return d[n-1][m-1];
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>a[i];
    if(bfs()==-1) cout<<"No"<<endl;
    else cout<<"Yes"<<endl;
    return 0;
}

P1162 填涂颜色

思路:

利用dfs把原来的0变成1,并且标记数组记住原来的0,方便后续输出

然后图中剩下的1就是1,剩下的0就是2,输出即可

#include<iostream>
using namespace std;
const int N=35;
int n,a[N][N],flag[N][N];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
void dfs(int x,int y){
    a[x][y]=1;
    flag[x][y]=1;
    if(a[x-1][y]==1){
        if(a[x][y+1]==1){
            if(a[x+1][y]==1){
                if(a[x][y-1]==1){
                    return ;
                }
            }
        }
    }
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(xx>0&&xx<=n&&yy>0&&yy<=n&&a[xx][yy]==0){
            dfs(xx,yy);
        }
    }
}
int main(){
    cin>>n;
    for(int i=0;i<=n+1;i++) a[0][i]=1,a[n+1][i]=1;
    for(int i=1;i<=n;i++) a[i][0]=-1,a[i][n+1]=-1;
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j];
    for(int i=1;i<=n;i++){
        if(a[1][i]==0) {flag[1][i]=1;dfs(1,i);}
        if(a[n][i]==0) {flag[n][i]=1;dfs(n,i);}
    }
    for(int i=1;i<=n-1;i++){
        if(a[i][1]==0) {flag[i][1]=1;dfs(i,1);}
        if(a[i][n]==0) {flag[i][n]=1;dfs(i,n);}
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(flag[i][j]) cout<<"0"<<" ";
            else{
                if(a[i][j]) cout<<"1"<<" ";
                else cout<<"2"<<" ";
            }
        }
        cout<<endl;
    }
    return 0;
}

P1506 拯救oibh总部

 和上面几题一样的思路dfs(AC):

#include<iostream>
using namespace std;
const int N=505;
int n,m,ans;
char a[N][N];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
void dfs(int x,int y){
    a[x][y]='*';
    if(a[x-1][y]=='*'&&x-1>=0&&x-1<n&&y>=0&&y<m-1){
        if(a[x][y+1]=='*'&&x>=0&&x<n&&y+1>=0&&y+1<m-1){
            if(a[x+1][y]=='*'&&x+1>=0&&x+1<n&&y>=0&&y<m-1){
                if(a[x][y-1]=='*'&&x>=0&&x<n&&y-1>=0&&y-1<m-1){
                    return ;
                }
            }
        }
    }
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(a[xx][yy]=='0'&&xx>=0&&xx<n&&yy>=0&&yy<m){
            dfs(xx,yy);
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<m;i++){
        if(a[0][i]=='0') dfs(0,i);
        if(a[n-1][i]=='0') dfs(n-1,i);
    }
    for(int i=1;i<n-1;i++){
        if(a[i][0]=='0') dfs(i,0);
        if(a[i][m-1]=='0') dfs(i,m-1);
    }
    for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(a[i][j]=='0') ans++;
    cout<<ans<<endl;
    return 0;
}

P8662 [蓝桥杯 2018 省 AB] 全球变暖

这题非常重要的一点是:原来的岛屿经过海水淹没后(只要没完全被淹没),仍然认为他们是同一座岛屿!!!

模拟下图样例:

海平面上升后:

答案为:4(原来有8个岛屿,红色是没有被完全淹没的,那么被完全淹没的就有4个)

因此思路是:先dfs所有原来的岛屿,接着dfs没被完全淹没的岛屿,最后相减得结果(AC):

#include<iostream>
using namespace std;
const int N=1005;
char a[N][N],b[N][N];
int n,res,ans;
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
void dfs_all(int x,int y){
    b[x][y]='.';
    if(b[x-1][y]=='.'&&x-1>=0&&x-1<n&&y>=0&&y<n){
        if(b[x][y+1]=='.'&&x>=0&&x<n&&y+1>=0&&y+1<n){
            if(b[x+1][y]=='.'&&x+1>=0&&x+1<n&&y>=0&&y<n){
                if(b[x][y-1]=='.'&&x>=0&&x<n&&y-1>=0&&y-1<n){
                    return ;
                }
            }
        }
    }
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(b[xx][yy]=='#'){
            dfs_all(xx,yy);
        }
    }
}
void dfs_rest(int x,int y){
    a[x][y]='.';
    if(a[x-1][y]=='.'&&x-1>=0&&x-1<n&&y>=0&&y<n){
        if(a[x][y+1]=='.'&&x>=0&&x<n&&y+1>=0&&y+1<n){
            if(a[x+1][y]=='.'&&x+1>=0&&x+1<n&&y>=0&&y<n){
                if(a[x][y-1]=='.'&&x>=0&&x<n&&y-1>=0&&y-1<n){
                    return ;
                }
            }
        }
    }
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(a[xx][yy]=='*'||a[xx][yy]=='#'){
            dfs_rest(xx,yy);
        }
    }
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++) for(int j=0;j<n;j++) {cin>>a[i][j];b[i][j]=a[i][j];}
    for(int i=0;i<n;i++) for(int j=0;j<n;j++) if(b[i][j]=='#') {dfs_all(i,j);res++;}
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(a[i][j]=='.'){
                for(int k=0;k<4;k++){
                    int x=i+dx[k],y=j+dy[k];
                    if(a[x][y]=='#') a[x][y]='*';
                }
            }
        }
    }
    for(int i=0;i<n;i++) for(int j=0;j<n;j++) if(a[i][j]=='#') {dfs_rest(i,j);ans++;}
    cout<<res-ans<<endl;
    return 0;
}

BFS(广搜)

模拟队列模板: 

typedef pair<int,int>pii;
int mapp[N][N];
int d[N][N];//每一个点到起点的距离
pii q[N*N];//手写队列
int bfs(){
    int hh=0,tt=0;
    q[0]={0,0};
    memset(d,-1,sizeof d);//距离初始化为-1表示没有走过
    d[0][0]=0;//表示起点走过了
    int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};//方向向量
    while(hh <= tt){//队列不空
        auto t=q[hh++];//取走队头元素
        for(int i=0;i<4;i++){//枚举4个方向
            int x=t.first+dx[i],y=t.second+dy[i];//更新方向
            if(x>=0&&x<n&&y>=0&&y<m&&mapp[x][y]==0&&d[x][y]==-1){//在边界内并且是空地并且之前没有走过
                d[x][y]=d[t.first][t.second]+1;//更新距离
                q[++tt]={x,y};//新坐标入队
            }
        }
    }
    return d[n-1][m-1];//右下角距起点的距离
}

STL模板:

typedef pair<int,int> pii;
int mapp[N][N],d[N][N];
int bfs(){
    queue<pii>q;
    q.push({0,0});
    memset(d,-1,sizeof d);
    d[0][0]=0;
    int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
    while(q.size()){
        auto t=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            int x=t.first+dx[i],y=t.second+dy[i];
            if(x>=0&&x<n&&y>=0&&y<m&&mapp[x][y]==0&&d[x][y]==-1){
                d[x][y]=d[t.first][t.second]+1;
                q.push({x,y});
            }
        }
    }
    return d[n-1][m-1];
}

打印路径模板:

typedef pair<int,int> pii;
int mapp[N][N],d[N][N];
pii preNode[N][N];//存储每个点的前一个点的坐标,方便追踪路径
int bfs(){
    queue<pii>q;
    q.push({0,0});
    memset(d,-1,sizeof d);
    d[0][0]=0;
    int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
    while(q.size()){
        auto t=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            int x=t.first+dx[i],y=t.second+dy[i];
            if(x>=0&&x<n&&y>=0&&y<m&&mapp[x][y]==0&&d[x][y]==-1){
                d[x][y]=d[t.first][t.second]+1;
                preNode[x][y]=t;//记录前驱点,是由t走到(x,y)的
                q.push({x,y});
            }
        }
    }
    return d[n-1][m-1];
}
void print_path(){
    if(d[n-1][m-1]==-1){
        cout<<"无法抵达终点"<<endl;
        return ;
    }
    vector<pii>path;
    //从终点遍历追踪
    for(pii x={n-1,m-1};x!=make_pair(0,0);x=preNode[x.first][x.second]) path.push_back(x);
    path.push_back({0,0});//加入起点
    reverse(path.begin(), path.end());//将路径逆序
    for(auto x:path) cout<<"("<<x.first<<","<<x.second<<")"<<"->";
    cout<<"终点"<<endl;
}

bfs练习:

B3626 跳跃机器人

一维路径问题 bfs(AC):

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N=1e6+5;
int n,d[N];
int bfs(){
    queue<int>q;
    q.push({1});
    memset(d,-1,sizeof d);
    d[1]=0;
    while(q.size()){
        auto t=q.front();
        q.pop();
        if(t-1>=1&&t-1<=n&&d[t-1]==-1){
            d[t-1]=d[t]+1;
            q.push({t-1});
        }
        if(t+1>=1&&t+1<=n&&d[t+1]==-1){
            d[t+1]=d[t]+1;
            q.push({t+1});
        }
        if(2*t>=1&&2*t<=n&&d[2*t]==-1){
            d[2*t]=d[t]+1;
            q.push({2*t});
        }
    }
    return d[n];
}
int main(){
    cin>>n;
    cout<<bfs()<<endl;
    return 0;
}

P2802 回家

二维路径问题+多种情况的判断 bfs(AC):

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=10;
int n,m,xbegin,ybegin;
struct point{   //结构体存储当前坐标状态
    int px,py,pstep,php;//坐标,步数,血量
};
int a[N][N];    //地图
bool flag[N][N];//标记经过鼠标
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
int bfs(int x,int y){
    queue<point>q;         //注意类型是结构体
    q.push(point{x,y,0,6});//出发点入队
    while(q.size()){
        auto t=q.front();  //取队头元素
        int x=t.px,y=t.py,step=t.pstep,hp=t.php;//初始化各变量
        q.pop();           //出队
        if(a[x][y]==3) return step;//走到家就结束
        if(hp>1){          //hp<=1时直接死亡
            for(int i=0;i<4;i++){
                int xx=x+dx[i],yy=y+dy[i];
                if(xx>=0&&xx<n&&yy>=0&&yy<m){//不能出界
                    if(a[xx][yy]==1||a[xx][yy]==3){//路和家直接走
                        q.push(point{xx,yy,step+1,hp-1});//入队
                    }
                    if(a[xx][yy]==4&&!flag[xx][yy]){//有鼠标的点最多只能走一次
                        flag[xx][yy]=true;//标记
                        q.push(point{xx,yy,step+1,6});//入队
                    }
                }
            }
        }
    }
    return -1;//无解返回-1
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>a[i][j];
            if(a[i][j]==2) xbegin=i,ybegin=j;
        }
    }
    cout<<bfs(xbegin,ybegin)<<endl;
    return 0;
}

P1135 奇怪的电梯

 这题会卡纯的dfs,当然也可以搜索每一条路后就更新答案再继续搜索(未AC 64points):

#include<iostream>
using namespace std;
int n,a,b,k[205],ans=1e6,flag[205];
//当前在第x楼,按了cnt次按钮
void dfs(int x,int cnt){
    if(cnt>=ans) return ;
    if(x==b){
        ans=min(ans,cnt);
        return ;
    }
    flag[x]=1;
    if(x+k[x]<=n&&flag[x+k[x]]==0){ //上楼
        flag[x+k[x]]=1;
        dfs(x+k[x],cnt+1);
        flag[x+k[x]]=0;
    }
    if(x-k[x]>=1&&flag[x-k[x]]==0){ //下楼
        flag[x-k[x]]=1;
        dfs(x-k[x],cnt+1);
        flag[x-k[x]]=0;
    }
}
int main(){
    cin>>n>>a>>b;
    for(int i=1;i<=n;i++) cin>>k[i];
    dfs(a,0);
    if(ans==1e6) {cout<<"-1"<<endl; return 0;}
    cout<<ans<<endl;
    return 0;
}

bfs(AC):

#include<iostream>
#include<queue>
using namespace std;
const int N=205;
int n,A,B,lift[N];
bool flag[N];
//标记数组作用是保证当前位置没有来过,因为如果回到原来经过的位置,那么就会一直重复
struct point{
    int loc,ans;//位置,当前已经走的步数
};
int bfs(int a,int b){
    queue<point>q;
    q.push(point{a,0});
    while(q.size()){
        auto t=q.front();
        int location=t.loc,step=t.ans;
        q.pop();
        if(location==b) return step;//到达终点
        if(location+lift[location]<=n){//可以向上
            if(!flag[location+lift[location]]){//并且该位置没有来过
                flag[location+lift[location]]=true;
                q.push(point{location+lift[location],step+1});
            }
        }
        if(location-lift[location]>=1){//可以向下
            if(!flag[location-lift[location]]){//并且该位置没有来过
                flag[location-lift[location]]=true;
                q.push(point{location-lift[location],step+1});
            }
        }
    }
    return -1;
}
int main(){
    cin>>n>>A>>B;
    for(int i=1;i<=n;i++) cin>>lift[i];
    cout<<bfs(A,B)<<endl;
    return 0;
}

P1747 好奇怪的游戏

这题注意初始化flag标记数组,并且把数组开大一点就没问题了

bfs(AC):

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=50;
int x1,y1,x2,y2;
int dx[12]={-2,-2,-1,-2,1,-2,2,-1,2,1,2,2};
int dy[12]={-2,-1,-2,1,-2,2,-2,2,-1,2,1,2};
bool flag[N][N];
struct point{
    int px,py,pstep;//坐标,步数
};
int bfs(int a,int b){
    queue<point>q;
    q.push(point{a,b,0});
    memset(flag,0,sizeof flag);
    flag[a][b]=true;
    while(q.size()){
        auto t=q.front();
        q.pop();
        int x=t.px,y=t.py,step=t.pstep;
        if(x==1&&y==1) return step;
        for(int i=0;i<12;i++){
            int xx=x+dx[i],yy=y+dy[i];
            if(xx>=1&&yy>=1){
                if(!flag[xx][yy]){
                    flag[xx][yy]=true;
                    q.push(point{xx,yy,step+1});
                }
            }
        }
    }
}
int main(){
    cin>>x1>>y1>>x2>>y2;
    cout<<bfs(x1,y1)<<endl;
    cout<<bfs(x2,y2)<<endl;
    return 0;
}

P1443 马的遍历

方法类似,只需要额外开一个二维答案数组存储步数即可

bfs(AC):

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=405;
int n,m,x,y;
int dx[8]={-2,-1,-2,1,-1,2,1,2};
int dy[8]={-1,-2,1,-2,2,-1,2,1};
int ans[N][N];//答案矩阵
bool flag[N][N];
struct point{
    int px,py;//坐标
};
void bfs(int a,int b){
    ans[a][b]=0;
    flag[a][b]=true;
    queue<point>q;
    q.push(point{a,b});
    while(q.size()){
        auto t=q.front();
        q.pop();
        int x=t.px,y=t.py;
        for(int i=0;i<8;i++){
            int xx=x+dx[i],yy=y+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m){
                if(!flag[xx][yy]){
                    flag[xx][yy]=true;
                    q.push(point{xx,yy});
                    ans[xx][yy]=ans[x][y]+1;
                }
            }
        }
    }
    return ;
}
int main(){
    cin>>n>>m>>x>>y;
    memset(ans,-1,sizeof ans);
    memset(flag,0,sizeof flag);
    bfs(x,y);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cout<<ans[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

P1746 离开中山路

bfs(AC):

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1005;
int n,x1,x2,y1,y2;
char a[N][N];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
bool flag[N][N];
struct point{
    int px,py,ps;
};
int bfs(int bx,int by,int ex,int ey){
    queue<point>q;
    q.push(point{bx,by,0});
    flag[bx][by]=true;
    while(q.size()){
        auto t=q.front();
        int x=t.px,y=t.py,step=t.ps;
        q.pop();
        if(x==ex&&y==ey) return step;
        for(int i=0;i<4;i++){
            int xx=x+dx[i],yy=y+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=n){
                if(a[xx][yy]=='0'){
                    if(!flag[xx][yy]){
                        flag[xx][yy]=true;
                        q.push(point{xx,yy,step+1});
                    }
                }
            }
        }
    }
    return -1;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j];
    cin>>x1>>y1>>x2>>y2;
    cout<<bfs(x1,y1,x2,y2)<<endl;
    return 0;
}

P3395 路障

这题整体思路不变,唯一要加的是唯一需要注意的是路障的处理,可开一个block数组存放在(x,y)位置路障将在什么时候放下,对于没有路障的点,直接走过,对于有路障的点,判断时间即可

bfs(AC):

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1005;
int T,n,a[N][N],block[N][N];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
bool flag[N][N];
struct point{
    int px,py,pt;//坐标,时间
};
bool bfs(){
    queue<point>q;
    q.push(point{1,1,0});
    flag[1][1]=true;
    while(!q.empty()){
        auto t=q.front();
        int x=t.px,y=t.py,timee=t.pt;
        q.pop();
        if(x==n&&y==n) return true;
        timee++;
        for(int i=0;i<4;i++){
            int xx=x+dx[i],yy=y+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=n){
                if(a[xx][yy]==0&&!flag[xx][yy]){
                    flag[xx][yy]=true;
                    if(!block[xx][yy]||timee<=block[xx][yy]){
                        q.push(point{xx,yy,timee});
                    }
                }
            }
        }
    }
    return false;
}
int main(){
    cin>>T;
    while(T--){
        memset(flag,0,sizeof flag);
        memset(block,0,sizeof block);
        memset(a,0,sizeof a);
        cin>>n;
        for(int i=1;i<=2*n-2;i++){
            int a1,b1;
            cin>>a1>>b1;
            block[a1][b1]=i;
        }
        if(bfs()) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}

P8673 [蓝桥杯 2018 国 C] 迷宫与陷阱

和 P2802 回家 类似,

三维状态数组+多种情况判断 bfs(AC):

#include<iostream>
#include<cstring>
#include<queue> 
using namespace std;
const int N=1005;
int n,k;
char a[N][N];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
//flag[x][y][z]:在剩余z个无敌时间时,有没有经过(x,y)
bool flag[N][N][11];
struct point{
    int px,py,ps,pk;//坐标,当前走的步数,剩余无敌的步数
};
int bfs(){
    queue<point>q;
    q.push({1,1,0,0});
    flag[1][1][0]=true;
    while(!q.empty()){
        auto t=q.front();
        q.pop();
        int x=t.px,y=t.py,step=t.ps,temp=t.pk;
        if(x==n&&y==n) return step;//到达终点,直接结束
        for(int i=0;i<4;i++){
            int xx=x+dx[i],yy=y+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=n){//保证边界
                if(a[xx][yy]!='#'){//墙是永远不可能经过的
                    //当前是未使用过的道具
                    if(a[xx][yy]=='%'&&!flag[xx][yy][k]){
                        flag[xx][yy][k]=true;
                        q.push({xx,yy,step+1,k});
                    }
                    //当前状态是无敌,道路和陷阱都可以走
                    if(temp>0&&!flag[xx][yy][temp-1]){
                        flag[xx][yy][temp-1]=true;
                        q.push({xx,yy,step+1,temp-1});
                    }
                    //当前状态不是无敌,道路可以走
                    if(temp==0&&a[xx][yy]=='.'&&!flag[xx][yy][0]){
                        flag[xx][yy][0]=true;
                        q.push({xx,yy,step+1,0});
                    }
                }
            }
        }
    }
    return -1;
}
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j];
    cout<<bfs()<<endl;
    return 0;
}

P1141 01迷宫

暴力bfs (超时未AC 70points):

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e3+5;
char a[N][N];
bool flag[N][N];
int n,m,ans;
int dx[4]={-1,0,1,0};
int dy[4]={0,-1,0,1};
int bfs(int tx,int ty){
    ans=1;
    flag[tx][ty]=1;
    queue<pair<int,int>>q;
    q.push({tx,ty});
    while(!q.empty()){
        auto t=q.front();
        int x=t.first,y=t.second;
        q.pop();
        for(int i=0;i<4;i++){
            int xx=x+dx[i],yy=y+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=n){
                if(!flag[xx][yy]&&a[xx][yy]!=a[x][y]){
                    flag[xx][yy]=1;
                    ans++;
                    q.push({xx,yy});
                }
            }
        }
    }
    return ans;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j];
    while(m--){
        int ax,bx;
        cin>>ax>>bx;
        memset(flag,0,sizeof flag);
        cout<<bfs(ax,bx)<<endl;
    }
    return 0;
}

优化思路:

联通块上每一个点的答案等于该联通块的数目

注意这里的联通块指的是四个方向上0,1相间隔的联通块,如下图,在搜 a[1][2] 时会经过6个点,而这6个点的答案是一样的,都是6,因此通过搜完联通块直接给联通块上的所有点存答案即可

 

因此可以考虑 dfs+记忆化搜索(AC):

#include<iostream>
using namespace std;
const int N=1e3+5;
char a[N][N];//地图
int ans[N][N];//答案数组为0表示没有搜过,大于0表示答案
int temp[N*N][2];//记忆化,存储坐标数组
int n,m,res;
int dx[4]={-1,0,1,0};
int dy[4]={0,-1,0,1};
void dfs(int x,int y){
    res++;//搜到,答案自增
    //记忆化:存储坐标
    temp[res][0]=x;
    temp[res][1]=y;
    //ans数组当前只起标记作用
    ans[x][y]=1;
    for(int i=0;i<4;i++){
        int xx=x+dx[i],yy=y+dy[i];
        if(xx>=1&&xx<=n&&yy>=1&&yy<=n){
            if(a[x][y]!=a[xx][yy]){
                if(!ans[xx][yy]){
                    dfs(xx,yy);
                }
            }
        }
    }
    return ;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j];
    while(m--){
        int ax,bx;
        cin>>ax>>bx;
        res=0;
        //已经存储过答案直接输出
        if(ans[ax][bx]) cout<<ans[ax][bx]<<endl;
        else{
            //否则搜素
            dfs(ax,bx);
            //记忆化:把路径上所有点的答案存储
            //ans数组正式记录所有答案
            for(int i=1;i<=res;i++)
                ans[temp[i][0]][temp[i][1]]=res;
            cout<<res<<endl;
        }
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/606351.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Python将数据表中的浮点数据转换为整数:详细教程与案例分析

目录 一、引言 二、环境准备 三、读取数据表 四、浮点数据转换为整数 五、写入数据表 六、案例分析 步骤一&#xff1a;读取数据表 步骤二&#xff1a;浮点数据转换为整数 步骤三&#xff1a;写入新的数据表 七、注意事项 八、总结 在数据处理和分析的过程中&#x…

58. 【Android教程】音频录制:MediaRecord

在第 57 节我们使用 MediaPlayer 实现了一个 mp3 播放器&#xff0c;除了播放 Android 还提供了 MediaRecorder 用于录音。Android 设备基本都会有一个麦克风&#xff0c;通过 MediaRecorder 可以打开麦克风进行语音采集&#xff0c;这一节我们就来学习如何在 Android 系统上实…

将ESP工作为AP路由模式并当成服务器

将ESP8266模块通过usb转串口接入电脑 ATCWMODE3 //1.配置成双模ATCIPMUX1 //2.使能多链接ATCIPSERVER1 //3.建立TCPServerATCIPSEND0,4 //4.发送4个字节在链接0通道上 >ATCIPCLOSE0 //5.断开连接通过wifi找到安信可的wifi信号并连接 连接后查看自己的ip地址变为192.168.4.…

太牛逼了,用ComfyUI中一键完成电商模特换装换背景!商业级教程附上!

&#x1f310; 大背景&#xff1a;电商时代的画卷正在翻页 在全球电子商务风起云涌的今天&#xff0c;市场竞争愈发激烈。商家们始终在寻求提高效率、减少成本和增强用户体验的新方法。然而&#xff0c;一个关键问题一直困扰着电商行业——**如何高效且经济地展示商品&#xff…

python如何整体缩进

python自带编辑器的缩进和取消缩进快捷键&#xff1a; 整体缩进 Ctrl【 整体取消缩进 Ctrl】 pycharm编辑器的缩进和取消缩进快捷键&#xff1a; 整体缩进&#xff1a; tab 整体取消缩进&#xff1a; tabshift

ADOP带你了解:温度如何影响您的室外以太网电缆?

温度&#xff1a;室外以太网电缆的隐形敌人 在构建和维护室外以太网网络时&#xff0c;我们通常会考虑到许多物理因素&#xff0c;如电缆的长度、宽带容量和连接质量。然而&#xff0c;有一个不那么显眼但同样重要的因素常常被忽视&#xff0c;那就是温度。温度的波动不仅影响…

力扣-21. 合并两个有序链表-js实现

/*** Definition for singly-linked list.* function ListNode(val, next) {* this.val (valundefined ? 0 : val)* this.next (nextundefined ? null : next)* }*/ /*** param {ListNode} list1* param {ListNode} list2* return {ListNode}*/ const mergeTwoList…

数据库索引回表困难?揭秘PolarDB存储引擎优化技术

引言 数据库系统为了高效地存储、检索和维护数据&#xff0c;采用了多种不同的数据组织结构。不同的组织结构有其特定的用途和优化点&#xff0c;比如提高查询速度、优化写入性能、减少存储空间等。常见的数据库记录组织结构有&#xff1a; B-Tree B-Tree是一种平衡的多路搜索…

【MySQL 数据宝典】【索引原理】- 007 索引优化示例

一、单表优化 1.1 数据准备 下面是一张用户通讯表的表结构信息,这张表来源于真实企业的实际项目中,有接近500万条数据. CREATE TABLE user_contacts (id INT(11) NOT NULL AUTO_INCREMENT,user_id INT(11) DEFAULT NULL COMMENT 用户标识,mobile VARCHAR(50) DEFAULT NULL C…

QT-小项目:连接MY SQL数据库实现登录(下一章实现登录注册账号和忘记密码功能)

一、环境准备 1、下载MYSQL 64位&#xff0c;安装完成&#xff0c;制作简易数据库教程如下&#xff1a; MY SQL安装 2、QT 编译器使用 二、实现工程目录&#xff08;基于上一章基础上&#xff09; 三、源程序增加内容如下&#xff1a; login.cpp 增加头文件&#xff1a; #in…

python代码自动生成器原理 python 生成器原理

python生成器原理剖析 函数的调用满足“后进先出”的原则&#xff0c;也就是说&#xff0c;最后被调用的函数应该第一个返回&#xff0c;函数的递归调用就是一个经典的例子。显然&#xff0c;内存中以“后进先出”"方式处理数据的栈段是最适合用于实现函数调用的载体&…

架空光缆用什么型号

架空光缆是什么意思 , 架空光缆用什么型号的 GYTC8A , 架空光缆型号是啥 8字形光缆 产品描述 Description GYTC8A光缆的结构是将250m光纤套入高模量材料制成的松套管中&#xff0c;松套管内填充防水化合物。缆芯的中心是一根金属加强芯&#xff0c;松套管(和填充绳 )围绕中心…

Davinci工程WrapNv模块讲解

配置讲解 WrapNv模块里面有两个东西&#xff0c;WrapNvGeneral和WrapNvMemoryLayout。 WrapNvGeneral里面配置的就是这个E方的基地址 WrapNvMemoryLayout里面就是分几个块来存储&#xff0c;每个块有自己的数据。 再里面一层&#xff0c;有各自的长度和默认值。我们可以在后面…

常见C语言基础说明二:位运算问题

一. 简介 前面一篇文章学习了 常见的 C语言基础题&#xff0c;文章如下&#xff1a; 常见C语言基础题说明一-CSDN博客 本文继续上一篇C语言基础题的学习。 二. C语言中 -> 位运算问题 1. 数据在计算机中的存储方式 当前的计算机系统使用的基本上是二进制系统&#…

Linux环境Redis部署

Redis部署 Redis是一个高性能的开源键值存储系统&#xff0c;它主要基于内存操作&#xff0c;但也支持数据的持久化。与其他数据库相比&#xff0c;Redis的主要优势在于它的高性能、丰富的数据结构和原生的持久化能力。Redis不仅提供了类似的功能&#xff0c;还增加了持久化和…

命令行方式将mysql数据库迁移到达梦数据库(全步骤)

因项目需求&#xff0c;需要将mysql数据库转换为国产达梦数据库&#xff0c;但由于安全问题&#xff0c;正式环境只能用命令行方式连接&#xff0c;下列是操作全步骤 目录 一、操作逻辑二、操作步骤1、本地安装达梦相关工具2、将服务器mysql导出到本地a) 服务器命令行导出mysql…

改进灰狼算法优化随机森林回归预测

灰狼算法&#xff08;Grey Wolf Optimization&#xff0c;GWO&#xff09;是一种基于自然界灰狼行为的启发式优化算法&#xff0c;在2014年被提出。该算法模仿了灰狼群体中不同等级的灰狼间的优势竞争和合作行为&#xff0c;通过不断搜索最优解来解决复杂的优化问题。 灰狼算法…

图:广度优先遍历(BFS)和深度优先遍历(DFS)

1.工具类&#xff1a;队列和字典 export class DictionNary {// 字典的封装constructor() {this.items {}}set(key, value) {// 添加键this.items[key] value}has(key){// 判断键是否存在return this.items.hasOwnProperty(key)}get(key){// 获取键的valuereturn this.has(k…

利用github pages建立Serverless个人博客

利用github pages建立Serverless个人博客 概述 使用github pages&#xff0c;可以在github上部署静态网站。利用这个功能&#xff0c;可以很方便地实现个人博客的发布托管。 比如我的个人博客&#xff1a;Buttering’s Blog 对应代码仓库&#xff1a;buttering/EasyBlog: 自…

MT3516W-ASEMI工业电源专用MT3516W

编辑&#xff1a;ll MT3516W-ASEMI工业电源专用MT3516W 型号&#xff1a;MT3516W 品牌&#xff1a;ASEMI 封装&#xff1a;MTW-5 最大重复峰值反向电压&#xff1a;1600V 最大正向平均整流电流(Vdss)&#xff1a;35A 功率(Pd)&#xff1a;大功率 芯片个数&#xff1a;5…