寒假c++学习第六弹——深度优先搜索(2021.02.02)

寒假c++学习第六弹——深度优先搜索(2021.02.02)

目录

迷宫最短路径

1.踏青

2.迷宫解方案数

3.最大的蛋糕块

4.家谱

5.马的覆盖点

6.王子救公主

7.蒜头君开公司


dfs求走出迷宫最短路径问题

//迷宫问题求最短路径问题(m行,n列的迷宫,1代表可走,2代表不可走,出发坐标(startx,starty),目标坐标(p,q))
#include <iostream>
using namespace std;
int maze[10][10]; //迷宫数组
int vis[10][10];  //访问数组,已访问为1,未访问为0
int mins = 100;
int m, n, startx, starty, p, q;
void dfs(int x, int y, int step){
    if(x == p && y == q){
        if(step < mins){
            mins = step;
            return;
        }
    }
    //向下
    if(maze[x+1][y] == 1 && vis[x+1][y] == 0){
        vis[x+1][y] = 1;
        dfs(x+1, y, step+1);
        vis[x+1][y] = 0;  //搜索完后恢复为0,以便下次搜索
    }
    //向左
    if(maze[x][y-1] == 1 && vis[x][y-1] == 0){
        vis[x][y-1] = 1;
        dfs(x, y-1, step+1);
        vis[x][y-1] = 0;
    }
    //向上
    if(maze[x-1][y] == 1 && vis[x-1][y] == 0){
        vis[x-1][y] = 1;
        dfs(x-1, y, step+1);
        vis[x-1][y] = 0;
    }
    //向右
    if(maze[x][y+1] == 1 && vis[x][y+1] == 0){
        vis[x][y+1] = 1;
        dfs(x, y+1, step+1);
        vis[x][y+1] = 0;
    }
    return;
}
int main()
{
    cin >> m >> n;
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            cin >> maze[i][j];
        }
    }
    cin >> startx >> starty >> p >> q;
    vis[startx][starty] = 1;
    dfs(startx, starty, 0);
    cout << mins << endl;
    return 0;
}

1.踏青

题目描述:

蒜头君和他的朋友周末相约去召唤师峡谷踏青。他们发现召唤师峡谷的地图是由一块一块格子组成的,有的格子上是草丛,有的是空地。草丛通过上下左右 4 个方向扩展其他草丛形成一片草地,任何一片草地中的格子都是草丛,并且所有格子之间都能通过上下左右连通。如果用'#'代表草丛,'.'代表空地,下面的峡谷中有 2 片草地。

##..

..##

处在同一个草地的 2 个人可以相互看到,空地看不到草地里面的人。他们发现有一个朋友不见了,现在需要分头去找,每个人负责一片草地,蒜头君想知道他们至少需要多少人。

输入格式:

第一行输入 n, m(1≤n,m≤100) 表示峡谷大小。

接下来输入 n 行字符串表示峡谷的地形。

输出格式:

输出至少需要多少人。

输入样例:

5 6
.#....
..#...
..#..#
...##.
.#....

输出样例:

5

参考代码

//本质是搜索有多少块草地
#include <iostream>
using namespace std;
int n, m, cnt=0;
char a[100][100]; //峡谷地图
bool vis[100][100]; //访问数组
void dfs(int x, int y){
    if(x >= n || y >= m || x < 0 || y < 0 || vis[x][y] || a[x][y] == '.'){
        return;
    }
    vis[x][y] = true;
    dfs(x+1, y);
    dfs(x, y-1);
    dfs(x-1, y);
    dfs(x, y+1);
}
int main(){
    cin >> n >> m;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            cin >> a[i][j];
        }
    }
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            if(!vis[i][j] && a[i][j] == '#'){
                dfs(i, j);
                cnt++;
            }
        }
    }
    cout << cnt << endl;
    return 0;
}

2.迷宫解方案数

题目描述:

蒜头君是一个玩迷宫的高手,天下还没有能难住他的迷宫。但是总有人喜欢刁难蒜头君,不停的给蒜头君出难题。这个出题的人很聪敏,他知道天下还没有能难住蒜头君的迷宫。所以他便转换思维问蒜头君,在不走重复路径的情况下,总共有多少不同可以到达终点的路径呢?蒜头君稍加思索便给出了答案,你要不要也来挑战一下?

输入格式:

第一行输入两个整数 n(1 ≤ n ≤ 11), m(1 ≤ m ≤ 11).表示迷宫的行和列。

然后有一个 n × m 的地图,地图由’.’、’#’、‘s’、‘e’这四个部分组成。’.‘表示可以通行的路,’#'表示迷宫的墙,'s’表示起始点,'e’表示终点。

输出格式:

输出一个整数,表示从’s’到达’e’的所有方案数。

输入样例:

5 5
s####
.####
.####
.####
….e

输出样例:

1

参考代码

//dfs求所有方案数
#include <iostream>
using namespace std;
char maze[10][10]; //迷宫数组
int vis[10][10];  //访问数组,已访问为1,未访问为0
int n, m, x, y, cnt=0;
void dfs(int x, int y){
    if(x >= n || y >= m || x < 0 || y < 0 || vis[x][y] || maze[x][y] == '#'){
        return;
    }
    if(maze[x][y] == 'e'){
        cnt++;
        return;
    }
    vis[x][y] = 1;
    //向下
    dfs(x+1, y);
    //向左
    dfs(x, y-1);
    //向上
    dfs(x-1, y);
    //向右
    dfs(x, y+1);
    vis[x][y] = 0;
    return;
}
int main()
{
    cin >> m >> n;
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            cin >> maze[i][j];
        }
    }
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            if(maze[i][j] == 's'){
                x = i;
                y = j;
            }
        }
    }
    dfs(x, y);
    cout << cnt << endl;
    return 0;
}

3.最大的蛋糕块

题目描述:

这一天蒜头君生日,他的朋友们一起来给蒜头君买一个大的蛋糕过生日。游戏做完后到了切蛋糕的时刻了,朋友们知道蒜头君喜欢吃蛋糕,便让蒜头君自己给自己切一块最大的。蒜头君看朋友们这么热情也就不客气了。

这块蛋糕是由 R \times CR×C 的网格构成,每个网格上面都放有不同的水果。蒜头君把这些水果分为两类,一类是自己喜欢吃的水果,用’#‘来表示;一类是自己不喜欢吃的水果,用’.'来表示。

蒜头君对切出的蛋糕有如下要求:

切出的蛋糕连成一块(可以不为矩形,但必须在网格上连通)
切出的蛋糕只包含自己喜欢吃的水果
请问,蒜头君最大可以吃到多大的蛋糕?

输入格式:

第一行输入两个被空格隔开的整数 R(1 \le R \le 1000)R(1≤R≤1000) 和 C(1 \le C \le 1000)C(1≤C≤1000)。

然后会有一个 R \times CR×C 的网格,由’#‘和’.'组成。

输出格式:

输出一个整数,表示蒜头君可以吃到的蛋糕最大是多少(即对应到网格中的格子数)。

输入样例:

5 6

.#....

..#...

..#..#

...##.

.#....

输出样例:

2

参考代码

//求最大联通
#include <iostream>
using namespace std;
int n, m, cnt, ans=0;
char a[100][100];
int vis[100][100];
void dfs(int x, int y){
    if(x >= n || y >= m || x < 0 || y < 0 || vis[x][y] || a[x][y] == '.'){
        return;
    }
    vis[x][y] = 1;
    cnt++;
    //向下
    dfs(x+1, y);
    //向左
    dfs(x, y-1);
    //向上
    dfs(x-1, y);
    //向右
    dfs(x, y+1);
    return;
}
int main()
{
    cin >> n >> m;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            cin >> a[i][j];
        }
    }
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            if(!vis[i][j] && a[i][j] == '#'){
                cnt = 0;
                dfs(i, j);
                if(cnt > ans){
                    ans = cnt;
                }
            }
        }
    }
    cout << ans;
    return 0;
}

4.家谱

题目描述:

输入一个n,接下来有n-1行。
输入父亲和儿子
求n个人,每个人的直系后代有多少。

输入格式:

输入一个n,接下来有n-1行。
输入父亲和儿子
求n个人,每个人的直系后代有多少。

输出格式:

输出n行,每行一个整数,表示第i个人有多少个直系后代

输入样例:

4

1 2

1 3

2 4

输出样例:

3

1

0

0

参考代码

#include <iostream>
#include <vector>
using namespace std;
vector<int> son[100005];
bool f[100005];
int ans[100005];
int dfs(int u){
    int ret = 0;
    for(int i=0; i<son[u].size(); i++){
        ret += dfs(son[u][i]);
    }
    ans[u] = ret;
    return ret + 1;
}
int main()
{
    int n, x, y, u;
    cin >> n;
    for(int i=1; i<=n-1; i++){
        cin >> x >> y;
        son[x].push_back(y);
        f[y] = true;
    }
    for(int i=1; i<=n; i++){
        if(!f[i]){
            u = i;
            break;
        }
    }
    dfs(u);
    for(int i=1; i<=n; i++){
        cout << ans[i] << endl;
    }
    return 0;
}

5.马的覆盖点

题目描述:

已知马走日,可以走八个方向,现用 · 表示可走的路,# 表示到达的点。
给出马的一个初始位置,请输出马在三步内可以到达的点(图来表示)。

输入格式:

第一行输入两个整数n(1 <= n <= 100), m(1 <= m <= 100)代表棋盘行数和列数,第二行输入两个整数x, y(不越界)代表马的初始位置。

输出格式:

输出整个棋盘,'.'表示棋盘上可以落子的点,'#'表示马走三步可以到达的点。

输入样例:

10 9

10 1

输出样例:

.........

.........

.........

.#.#.....

#.#.#....

####.#...

#####.#..

##.###...

#.###.#..

######...

参考代码

#include <iostream>
using namespace std;
char s[105][105];
int n, m;
int dir[8][2] = {{-2, -1}, {-2, 1}, {2, -1}, {2, 1}, {1, 2}, {1, -2}, {-1, 2}, {-1, -2}};
void dfs(int x, int y, int step){
    if(step > 3){
        return;
    }
    if(x < 0 || x >= n || y < 0 || y >= m){
        return;
    }
    s[x][y] = '#';
    for(int i=0; i<8; i++){
        dfs(x+dir[i][0], y+dir[i][1], step+1);
    }
}
int main()
{
    int x, y;
    cin >> n >> m >> x >> y;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            s[i][j] = '.';
        }
    }
    dfs(x-1, y-1, 0);
    for(int i=0; i<n; i++){
        cout << s[i] << endl;
    }
    return 0;
}

6.王子救公主

题目描述:

一天,蒜头君梦见自己当上了王子,但是不幸的是,自己的公主被可恶的巫婆抓走了。于是蒜头君动用全国的力量得知,自己的公主被巫婆抓进一个迷宫里面。由于全国只有蒜头君自己可以翻越迷宫外的城墙,蒜头君便自己一人走上的拯救自己公主的路途。

碰巧的是巫婆出去了,迷宫也不大,蒜头君可以直接和公主对话,于是两个人便开始相互靠近。每一步移动只能朝着上下左右四个方向走一格,不能走进墙所在的位置。蒜头君救公主心切,一次必须沿着一个方向走两步(允许跨越迷宫中的墙);公主柔弱,一次只能走一步。问在这个迷宫中,蒜头君是否可以救出公主(蒜头君和公主相遇后,就能背着公主逃出迷宫了)。

输入格式:

第一行输入两个整数 n(1≤n≤100), m(1≤m≤100) 表示迷宫的行和列。

然后有一个 n×m 的地图,地图由'.''#''w''g'这四个部分组成。'.'表示可以通行的路,'#'表示迷宫的墙,'w'表示王子开始所在的位置,'g'表示公主开始所在的位置。

输出格式:

输出王子是不可以救出自己的公主,如果能救出则输出"yes",否则输出"no"

输入样例:

1 8
w....#.g

输出样例:

yes

参考代码

//需要两次搜索,分别表示王子和公主走过的路,然后看看是否他们可以走过同一个位置,如果可以,说明可以救出
#include <iostream>
using namespace std;
char mp[105][105];
bool vis[105][105][2];
int n, m;
void dfs(int x, int y, int d){
    if(x < 0 || x>=n || y<0 || y>=m || vis[x][y][d] || mp[x][y] == '#'){
        return;
    }
    //d=0为王子,d=1为公主
    vis[x][y][d] = true;
    dfs(x - (2-d), y, d);
    dfs(x + (2-d), y, d);
    dfs(x, y - (2-d), d);
    dfs(x, y + (2-d), d);
}
int main()
{
    int x, y;
    bool ans;
    cin >> n >> m;
    for(int i=0; i<n; i++){
        cin >> mp[i];
    }
    //王子
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            if(mp[i][j] == 'w'){
                x = i;
                y = j;
            }
        }
    }
    dfs(x, y, 0);
    //公主
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            if(mp[i][j] == 'g'){
                x = i;
                y = j;
            }
        }
    }
    dfs(x, y, 1);
    ans = false;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            if(vis[i][j][0] && vis[i][j][1]){
                ans = true;
            }
        }
    }
    if(ans){
        cout << "yes" << endl;
    }
    else{
        cout << "no" << endl;
    }
    return 0;
}

7.蒜头君开公司

题目描述:

2020 年,蒜头君自己开了一家拥有 N 个员工的大公司。每天,蒜头君都要分配 N 项工作给他的员工,但是,由于能力的不同,每个人对处理相同工作所需要的时间有快有慢。众所周知,蒜头君是一个非常重视效率的人,他想知道该如何分配工作,才能使得完成所有工作的时间总和最小(每个员工只可以被分配到一个工作)。但是我们也都知道蒜头君不是一般的懒,所以蒜头君找到了你,请你拯救一下蒜头君吧!

输入格式:

第一行输入一个整数 N,代表有 N 个员工,员工编号从 1 到 N。(1≤N≤10)
接着输入一个 N∗N的二维矩阵 task[N][N],task[i][j] 指的是第 i 项工作如果由 j 号员工完成所需要的时间。(0≤task[i][j]≤1000)

输出格式:

输出结果包括一个整数,代表所需要的最少时间(求和)。

输入样例:

6
10 11 12 11 9 11
11 9 10 13 11 12
12 10 11 10 13 9
9 14 9 10 10 11
10 10 9 11 12 11
10 7 10 10 10 8

输出样例:

54

参考代码

#include <iostream>
using namespace std;
int task[15][15];
//每一列代表一个员工
bool used[15];
int ans;  //最少时间总和
int n;
void dfs(int x, int t){ //员工与当前所用时间
    if(x == n){
        if(t < ans){
            ans = t;
        }
        return;
    }
    for(int i=0; i<n; i++){
        if(!used[i]){
            used[i] = true;
            dfs(x + 1, t + task[x][i]);
            used[i] = false;
        }
    }
}
int main()
{
    cin >> n;
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            cin >> task[i][j];
        }
    }
    ans = 20000;
    dfs(0, 0);
    cout << ans;
    return 0;
}

如有错误欢迎指正,题目来源:计蒜客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值