【洛谷】普及练习场 深度优先搜索【易】

 

P1219 八皇后

题目大意:

给出一个n*n的正方形棋盘,在上棋盘上放下n个皇后,要求每个皇后所在的行,列,两条对角线上没有其他皇后,输出前三种解法(按字典序排,输出结果从上到下用列号表示),并且最后输出解的个数。

 

输入格式:

一个数字N (6 <= n <= 13) 表示棋盘是n * n大小的。

 

输出格式:

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

 

输入样例1:

6

输出样例1:

2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4

分析:
对角线的表示方法(画个图就明白了),通过标记找符合的位置,找到一种解法后清除去除行以外的所有标记记录,行的记录不用清除是为了避免解的重复。

代码:
#include<iostream>
using namespace std;

int a[100];//
int b[100];//
int c[100];//
int d[100];//

int total;//可行解的个数
int n;

void dfs(int i){
    if(i>n){//在棋盘上成功放下n个皇后
        if(total<=2){//total从0开始,满2即输出前三个解
           for(int k=1;k<=n;k++)
              cout<<a[k]<<" ";
           cout<<endl;
        }
        total++;//记录解的个数
        return;
    }
    else{
        for(int j=1;j<=n;j++){
            if((!b[j])&&(!c[i+j])&&(!d[i-j+n])){//d数组中加n是为了避免出现负数
                a[i]=j;//在i行j列找到一个符合条件的位置放下一个皇后
                b[j]=1;//标记列被占领
                c[i+j]=1;
                d[i-j+n]=1;
                dfs(i+1);
                //return之后,回到之前的每一层执行下面三句,清除除行之外所有标记
                b[j]=0;
                c[i+j]=0;
                d[i-j+n]=0;
            }
        }
    }
}
int main(){
    cin>>n;
    dfs(1);
    cout<<total<<endl;
    return 0;
}
View Code

 在洛谷题解中看到有位大佬用了位运算+__builtin函数优化的方法,看评论区说大概是全洛谷最快了,不过我没看懂orz

 

P1101 单词方阵

题目大意:

给一n×n的字母方阵,内可能蕴含多个“yizhong”单词。单词在方阵中是沿着同一方向连续摆放的。摆放可沿着 8个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间可以交叉,因此有可能共用字母。输出时,将不是单词的字母用*代替,以突出显示单词。

 

输入格式:

第一行输入一个数n。(7n100)。

第二行开始输入n×n的字母矩阵。

 

输出格式: 

突出显示单词的n×n矩阵。

 

输入样例1:

8
qyizhong
gydthkjy
nwidghji
orbzsfgz
hhgrhwth
zzzzzozo
iwdfrgng
yyyygggg

输出样例1:

*yizhong
gy******
n*i*****
o**z****
h***h***
z****o**
i*****n*
y******g

分析:

刚接触dfs不久看的题大多是像迷宫这样的,这题一下子没反应过来是一条路做到黑,感觉有点像嵌套的dfs,外面那个负责方向的改变,里面那个在确定方向后一直走,找到完整字符串后要注意回溯标记。个人感觉这道题还不错(大佬请忽略这句话,在本菜鸡眼里可能不存在水题。

代码:

#include<iostream>
#include<string.h>
using namespace std;
int n;
char a[100][100];
char str[]={"yizhong"};
int vis[100][100];
int b[100][100];
int dx[8]={1,-1,0,0,1,1,-1,-1};//x方向
int dy[8]={0,0,1,-1,1,-1,-1,1};//y方向
void dfs(int x,int y,int gx,int gy,int d){
        if(d==6&&a[x][y]=='g'){
            vis[x][y]=1;
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(vis[i][j]==1)
                        b[i][j]++;//记录可以成功构成”yizhong“的坐标
                }
            }
            vis[x][y]=0;
            return;
        }
        int nx=x+gx;
        int ny=y+gy;
        //选定方向后寻找下一个字母
        if(nx>=0&&nx<n&&ny<n&&ny>=0&&a[nx][ny]==str[d+1]){
            vis[nx][ny]=1;
            dfs(nx,ny,gx,gy,d+1);
            vis[nx][ny]=0;
        }
}

int main(){
    cin>>n;
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++){
        cin>>a[i][j];
    }
    memset(vis,0,sizeof(vis));
    memset(b,0,sizeof(b));
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(a[i][j]=='y'){//遍历搜索'y'
                for(int k=0;k<8;k++){//八个方向”选定方向后一条路走到黑“
                    vis[i][j]=1;//标记
                    dfs(i,j,dx[k],dy[k],0);
                    vis[i][j]=0;
                }
            }
        }
    }
    //输出结果
    for(int h=0;h<n;h++){
        for(int k=0;k<n;k++){
            if(b[h][k]==0)
                cout<<'*';
            else
                cout<<a[h][k];
        }
        cout<<endl;
    }
    return 0;
}
View Code

 

P1605 迷宫

题目大意:

给定一个n*m方格的迷宫,迷宫里有 t 处障碍,障碍处不可通过。给定起点坐标和终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。

 

输入格式:

 第一行n、m(1≤n,m≤5)和 t,n为行,m为列,T为障碍总数。第二行起点坐标sx,sy,终点

坐标ex,ey。接下来 t 行,每行为障碍点的坐标。

 

输出格式:

给定起点坐标和终点坐标,问每个方格最多经过1次,从起点坐标到终点坐标的方

案总数。

 

输入样例1:

2 2 1
1 1 2 2
1 2

输出样例1:

1

分析:

迷宫这一类题目算是dfs和bfs中的经典题目,“加强版”也有很多,这题应该是最简单的版本的吧。

需要注意:每个方格至多经历一次,所以要对路径进行标记,避免重复走,每找出一个方案都要对走过的路径回溯时撤销标记。 

代码:

#include<iostream>
#include<string.h>
using namespace std;
int n,m,t,a,b;
int sx,sy,ex,ey;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int ans=0;
int Map[50][50];//标记障碍
int c[50][50];//标记走过的方格
void dfs(int x,int y){
    if(x==ex&&y==ey){
        ans++;//记录方案的数目
        return;
    }
    for(int i=0;i<4;i++){
        int nx=x+dx[i];
        int ny=y+dy[i];
        if(ny>0&&ny<=n&&nx>0&&nx<=m&&Map[nx][ny]==0&&c[nx][ny]==0){
            c[nx][ny]=1;
            dfs(nx,ny);
            c[nx][ny]=0;//回溯清除标记
        }
    }
}
int main(){
    cin>>n>>m>>t;
    cin>>sx>>sy>>ex>>ey;
    memset(Map,0,sizeof(Map));
    memset(c,0,sizeof(c));
    c[sx][sy]=1;
    for(int i=1;i<=t;i++){
        cin>>a>>b;
        Map[a][b]=1;
    }
    dfs(sx,sy);
    cout<<ans<<endl;
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/l-yt/p/10825353.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值