[AcWing算法刷题]之DFS+BFS迷宫模板(简单)

题目来源:

题库 - AcWing

目录

DFS和BFS模板题目:迷宫类

        机器人的运动范围​

        字母

        迷宫

        红与黑

        棋盘问题

        马走日

        全球变暖

DFS综合类

        乘积最大(提高课)

        单词接龙(提高课)

        取石子游戏(dfs数学推理)


机器人的运动范围

 BFS:

class Solution {
public:

    int get_sum(pair<int, int> p) {
        int s = 0;
        while (p.first) {
            s += p.first % 10;
            p.first /= 10;
        }
        while (p.second) {
            s += p.second % 10;
            p.second /= 10;
        }
        return s;
    }

    int movingCount(int threshold, int rows, int cols)
    {
        if (!rows || !cols) return 0;
        queue<pair<int,int>> q;
        vector<vector<bool>> st(rows, vector<bool>(cols, false));

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

        int res = 0;
        q.push({0, 0});
        while (q.size()) {
            auto t = q.front();
            q.pop();
            if (st[t.first][t.second] || get_sum(t) > threshold) continue;
            res ++ ;
            st[t.first][t.second] = true;
            for (int i = 0; i < 4; i ++ ) {
                int x = t.first + dx[i], y = t.second + dy[i];
                if (x >= 0 && x < rows && y >= 0 && y < cols) q.push({x, y});
            }
        }

        return res;
    }
};

DFS:

class Solution {
public:
int k;
int b,a;
int f[52][52];
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
    int movingCount(int threshold, int rows, int cols)
    {
        memset(f,false,sizeof f);
        b=cols,a=rows;

         int res=0;

        k=threshold;

        return    dfs(0,0);
    }
    int dfs(int y,int x)
    {
        if(x<0||x>=a||y<0||y>=b||f[y][x]) return 0;

         f[y][x]=true;
        int res=0;
        int x1=x,y1=y;
        while(x1)
        {
            res+=(x1%10);
            x1/=10;
        }
         while(y1)
        {
            res+=(y1%10);
            y1/=10;
        }

        if(res>k) return 0;
        int sum=0;

        for(int i=0;i<4;i++)
        {
            int q=x+dx[i],p=y+dy[i];
            sum+=dfs(p,q);
        }


         return sum+1;
    }
};

作者:dfbdberberb
链接:https://www.acwing.com/solution/content/11722/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

乘积最大(较难)

 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int n, k, ans;
string str;
bool st[20];//标记数字是否出现过
vector<int>num;//存放分割的数字

int number(int l, int r)//求区间[l,r]的数字
{
    int res = 0;
    for (int i = l; i <= r; i++)
        res = res * 10 + str[i] - '0';
    return res;
}

void dfs(int pos, int cnt)//枚举到的第几个空位,乘号的当前个数
{
    if (cnt == k)//如果乘号个数==题目所给的乘号个数
    {
        int y = number(pos, n - 1);//求出分割k次以后,第k+1个数的大小
        num.push_back(y);//放入分割的数字中
        int tmp = 1;
        for (int i = 0; i < num.size(); i++)//求乘积
            tmp *= num[i];
        //          cout<<num[i]<<" ";
        //      cout<<endl;
        ans = max(ans, tmp);//更新最大值
        num.pop_back();
        return;
    }
    for (int i = 0; i < n - 1; i++)//枚举分割位置
    {
        if (!st[i] && pos <= i)//如果分割位置未出现过,向下搜索
        {
            int x = number(pos, i);
            num.push_back(x);
            st[i] = true;
            dfs(i + 1, cnt + 1);
            st[i] = false;
            num.pop_back();
        }
    }
}

int main()
{
    cin >> n >> k;
    cin >> str;
    dfs(0, 0);
    cout << ans << endl;
    return 0;
}

字母

 

 BFS:

需要额外开一个字母数组来哈希快速找到该字母是否之前已经走过

#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<memory.h>
#include<cstring>
using namespace std;

int n, m;
const int N = 50;
vector<string> V;
int mp[26];

struct STATE {
	int x, y;
	int mp[26];
	int step;
};

int ans = -1;
int addx[4] = { 1,-1,0,0 };
int addy[4] = { 0,0,-1,1 };

void bfs()
{
	queue<struct STATE> q;
	struct STATE s;
	memset(s.mp, 0, sizeof s.mp);
	s.mp[V[0][0] - 'A'] = 1;//标记
	s.step = 1;
	s.x = 0, s.y = 0;

	q.push(s);
	while (q.size())
	{
		auto t = q.front();
		q.pop();
		ans = max(ans, t.step);
		
		for (int i = 0; i < 4; i++)
		{
			int newx = t.x + addx[i];
			int newy = t.y + addy[i];
			
			if (newx >= 0 && newx < n && newy >= 0 && newy < m)
			{
				int idx = V[newx][newy] - 'A';
				if (t.mp[idx] == 1) continue;
				struct STATE next;
				next.x = newx;
				next.y = newy;
				next.step = t.step + 1;
				memcpy(next.mp, t.mp, sizeof t.mp);
				next.mp[idx] = 1;

				q.push(next);
			}
		}
	}
}

int main()
{
	cin >> n >> m;

	for (int i = 0; i < n; i++)
	{
		string s;
		cin >> s;
		V.push_back(s);
	}

	bfs();
	cout << ans << endl;

	return 0;
}

DFS:

同样需要开一个字母数组,来判断该字母是否出现过

不同的地方在与DFS搜索迷宫具有对称性:标记(   )搜索下一层(  )取消标记

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

int n, m;
const int N = 50;
vector<string> V;
int mp[26];
int ans = -1;

int addx[] = { 1,-1,0,0 };
int addy[] = { 0,0,-1,1 };

void dfs(int x, int y, int step)
{
	int idx = V[0][0] - 'A';
	mp[idx] = 1;

	for (int i = 0; i < 4; i++)
	{
		int newx = x + addx[i];
		int newy = y + addy[i];

		if (newx >= 0 && newx < n && newy >= 0 && newy < m)
		{
			int idx = V[newx][newy] - 'A';
			if (mp[idx] == 1) continue;
			mp[idx] = 1;
			dfs(newx, newy, step + 1);
			mp[idx] = 0;
		}
	}
	ans=max(ans,step);
}

int main()
{
	cin >> n >> m;

	for (int i = 0; i < n; i++)
	{
		string s;
		cin >> s;
		V.push_back(s);
	}

	dfs(0, 0, 1);
	cout << ans << endl;

	return 0;
}

迷宫

 

 BFS:

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;

typedef pair<int, int> PII;
const int N = 110;
int n;
char g[N][N];
bool st[N][N];
queue<PII> q;
int startx, starty;
int endx, endy;

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

void bfs()
{
	q.push({ startx,starty });
	st[startx][starty]=true;
	while (q.size())
	{
		auto t = q.front();
		q.pop();
		
		for (int i = 0; i < 4; i++)
		{
			int x = t.first + dx[i];
			int y = t.second + dy[i];
			if (x >= 0 && x < n && y>=0 && y < n && !st[x][y] && g[x][y] == '.')
			{
				st[x][y] = true;
				q.push({ x,y });
			}
			else continue;
		}
	}
}

int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		cin >> n;
		for (int i = 0; i < n; i++) cin >> g[i];

		cin >> startx >> starty;
		cin >> endx >> endy;

		bfs();
		
        if(g[startx][starty]=='#' || g[endx][endy]=='#' || !st[endx][endy])cout << "NO" << endl;
		else if (st[endx][endy]) cout << "YES" << endl;
		

		memset(st, false, sizeof st);
	}

	return 0;
}

DFS:

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

using namespace std;

const int N = 110;

char g[N][N];
bool st[N][N];
int n;
int l1, r1, l2, r2;
int dx[] = {0, -1, 0, 1}, dy[] = {-1, 0, 1, 0};
bool dfs(int x, int y)
{
    if(x == l2 && y == r2)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(g[a][b] == '#')continue;
        if(st[a][b])continue;
        if(dfs(a, b))return true;
    }
    return false;
}

int main()
{
    int T;
    cin >> T;
    while(T --)
    {
        memset(st, false, sizeof st);
        cin >> n;
        for(int i = 0; i < n; i ++) cin >> g[i];
        cin >> l1 >> r1 >> l2 >> r2;
        if(g[l1][r1] == '#' || g[l2][r2] == '#')
        {
            puts("NO");
            continue;
        }
        if(dfs(l1, r1))puts("YES");
        else puts("NO");
    }
    return 0;
}

红与黑

 

 DFS:

#include<iostream>
#include<cstring>
using namespace std;
const int N=25;
char g[N][N];
bool st[N][N];
int n,m;
int dx[4]={-1,0,1,0};
int 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];
        int 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);
    }
    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;
}

棋盘问题

 

//DFS
//类似于八皇后的一道多了一些限制的题

#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

const int N = 20;

char g[N][N];                                       //存储输入棋盘 
int ans;                                            //存储答案 
int n, k;
int m;                                              //存储已近放入棋盘的棋子数 
bool line[N];                                       //存储当前列上有没有其他棋子 

void dfs(int x)
{
    if(m == k)                                      //当棋子放光的时候 
    {
        ans++;
        return;
    }

    if(x == n)                                      //防止越界 
        return;
    
    dfs(x + 1);     //这个是关键,因为 k <= m,因此可能有行不用放棋子,所以我们要手动舍弃行,直接进入下一行 
    for(int i = 0; i < n; i++)                      //爆搜 
        if(!line[i] && g[x][i] == '#')
        {
            line[i] = true;
            m++;                                    //记录放入的棋子数 
            dfs(x + 1);
            line[i] = false;                        //还原初始状态 
            m--;
        }

    
}

int main()
{
    while(scanf("%d%d", &n, &k) && n != -1 && k != -1)
    {
        ans = m = 0;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                cin >> g[i][j];

        dfs(0);
        cout << ans << endl;
    }

    return 0;
}

取石子游戏

 

#include<iostream>
#include<algorithm>
using namespace std;

int n, m;

void dfs(int a, int b, int step)
{
	if (a % b == 0 || a / b >= 2)
	{
		if (step & 1)
		{
			cout << "win" << endl;
			return;
		}
		else
		{
			cout << "lose" << endl;
			return;
		}
	}
	dfs(b, a % b, step + 1);
}

int main()
{
	while (cin >> n >> m, n || m)
	{
		if (n < m) swap(n, m);
		if (n / m >= 2) cout << "win" << endl;
		else dfs(n, m, 1);
	}

	return 0;
}

马走日

#include<bits/stdc++.h>
using namespace std;
int T,n,m,a,b,ans;
int vis[20][20];
int dx[8]={2,1,-1,-2,-2,-1,1,2};//方向数组
int dy[8]={1,2,2,1,-1,-2,-2,-1};//方向数组
void dfs(int x,int y,int step)//step记录当前走了几个格子
{
    if(step==n*m){//已遍历完所有的格子
        ans++;//答案加一
        return;
    }
    for(int i=0;i<8;i++){
        int kx=x+dx[i];
        int ky=y+dy[i];
        if(kx>=0&&kx<n&&ky>=0&&ky<m&&vis[kx][ky]==0){//判断
            vis[kx][ky]=1;//标记
            dfs(kx,ky,step+1);
            vis[kx][ky]=0;//回溯
        }
    }
}
int main()
{
    scanf("%d",&T);
    while(T--){//多组测试数据
        ans=0;//一定要记得清空数据
        memset(vis,0,sizeof(vis));
        scanf("%d %d %d %d",&n,&m,&a,&b);
        vis[a][b]=1;//标记起点
        dfs(a,b,1);
        printf("%d\n",ans);
    }
    return 0;
}

单词接龙(提高课)

 

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

using namespace std;

const int N = 21;

int n;
string word[N];
int g[N][N];//代表编号i的可以被j拼接  如i:asd,j:sdf,拼接长度为最小值g[i][j] = 2,i从0开始记位
int used[N];//编号为i的单词使用次数
int ans;

void dfs(string dragon, int last)
{
    ans = max((int)dragon.size(), ans);//取最大值,dragon.size()为当前合并的长度

    used[last]++;//编号为last的单词被用次数++;

    for (int i = 0; i < n; i++)
        if (g[last][i] && used[i] < 2)//used[i]<2代表单词用次数不超过2
            dfs(dragon + word[i].substr(g[last][i]), i); //编号为last的可以被i拼接现在尾巴为i号

    used[last]--;//恢复现场
}

int main() {
    cin >> n;
    for (int i = 0; i < n; i++) cin >> word[i];
    char start;
    cin >> start;//首字母

    for (int i = 0; i < n; i++)//遍历得到各个g[i][j]
        for (int j = 0; j < n; j++) {
            string a = word[i], b = word[j];
            for (int k = 1; k < min(a.size(), b.size()); k++)
                if (a.substr(a.size() - k, k) == b.substr(0, k)) {
                    g[i][j] = k;
                    break;
                }
        }

    for (int i = 0; i < n; i++)//找到首字母为strat的单词开始做dfs,dfs中会自动找到最大值
        if (word[i][0] == start)
            dfs(word[i], i);//从word[i]开始遍历,i代表现在是第几个单词

    cout << ans << endl;

    return 0;
}

全球变暖

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;
int n;
char g[N][N];
bool st[N][N];
PII q[N * N];
int dx[4] = { -1,0,1,0 };
int dy[4] = { 0,1,0,-1 };
// total : 岛屿的板块的数量  bound:邻接海洋的岛屿板块的数量
void bfs(int sx, int sy, int& total, int& bound)
{
	int hh = 0;
	int tt = 0;
	q[0] = { sx,sy };
	st[sx][sy] = true;

	while (hh <= tt)
	{
		PII t = q[hh++];

		total++;
		bool is_bound = false;
		for (int i = 0; i < 4; i++)
		{
			int x = t.x + dx[i];
			int y = t.y + dy[i];
			if (x < 0 || x >= n || y < 0 || y >= n) continue;
			if (st[x][y]) continue;//如果已经走过了
			if (g[x][y] == '.')//上下左右之中有一个为海
			{
				is_bound = true;
				continue;
			}
			q[++tt] = { x,y };
			st[x][y] = true;
		}
		if (is_bound) bound++;//只要上下左右之中有一个为海,那么它就是边界
	}
}

int main()
{
	cin >> n;

	for (int i = 0; i < n; i++) cin >> g[i];

	int cnt = 0;
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			if (!st[i][j] && g[i][j] == '#')
			{
				int total = 0;
				int bound = 0;
				bfs(i, j, total, bound);
				if (total == bound) cnt++;
			}
	cout << cnt << endl;

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值