算法训练三(DFS、BFS、回溯)(含模板)(上)

目录

7-1 有序部分排列(回溯法)

AC代码:

7-2 有重复元素的全排列(回溯法)

AC代码:

7-3 找零钱***(回溯法)

AC代码:

7-4 整数拆分(回溯法)

AC代码:

7-5 数字三角形问题(动态规划)

AC代码:

7-6 幂集(回溯法)

AC代码:

7-7 子集和问题(回溯/深度优先搜索)

AC代码:

7-8 工作分配问题(回溯/深度优先搜索)

AC代码: 

7-9 岛屿数量(深度优先搜索)

AC代码:

7-10 小H喜欢睡觉(广度优先搜索)

AC代码:

7-11 迷宫问题(深度优先搜索)

AC代码:

7-12 走迷宫Ⅱ(广度优先搜索+优先队列)

AC代码:

7-14 h0252.拯救行动(广度优先搜索)

AC代码:


对于回溯算法、dfs、bfs算法,都属于是暴力搜索法的一种,均有固定的模板,这里建议读者在写这类题的同时优先了解此类算法,然后再进行刷题

这里回溯算法可以学习该博主的文章:

「leetcode」最强回溯算法总结篇!历时21天、画了20张树形结构图、14道精选回溯题目精讲_代码随想录的博客-CSDN博客

迷宫问题的dfs、bfs模板我之前有总结过

迷宫问题 (dfs深度优先搜索)【模板】_清晨喝碗粥的博客-CSDN博客

迷宫问题(bfs广度优先搜索)【模板】_清晨喝碗粥的博客-CSDN博客

由于题集题目较多,下半部分请移步这里:

算法训练三(DFS、BFS、回溯)(含解题思路)(下)_清晨喝碗粥的博客-CSDN博客 

7-1 有序部分排列(回溯法)

对于1~n这n个不同的数,按照一定的顺序把其中m个数排列起来(每个数最多出现一次,m

输入格式:

一个数n和m。

输出格式:

输出按字典序的有序部分排列,每行的数间用一个空格隔开,最后一个数后有空格。最后多出一行空格

输入样例:

5 3

输出样例:

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

AC代码:

#include
using namespace std;
void dfs(vector> &nums, vector &v, int n, int m, int index) {
	if (v.size() == m) {
		nums.push_back(v);
		return;
	}
	int i;
	for (i = index; i <= n; i++) {
		v.push_back(i);
		dfs(nums, v, n, m, i + 1);
		v.pop_back();
	}
}
int main()
{
	int i, j, k, n, m;
	cin >> n >> m;
	vector>nums;
	vectorv;
	dfs(nums, v, n, m, 1);
	for (i = 0; i < nums.size(); i++) {
		for (j = 0; j < nums[i].size(); j++) {
				cout << nums[i][j] << " ";
		}
		cout << endl;
	}

	system("pause");
	return 0;
}

7-2 有重复元素的全排列(回溯法)

计算给定的n个数有多少种排列方式,即求全排列(可能出现重复的元素)

输入格式:

第一行输入数字的数量n(n>2),第二行给出每一个数字。

输出格式:

一个数字,不同排列方式的数量。

输入样例:

3
1 2 2

输出样例:

3

AC代码:

#include
using namespace std;
void dfs(vector &v, vector &temp, vector &nums, int &count) {
	if (v.size() == nums.size()) {
		count++;
		return;
	}
	for (int i = 0; i < nums.size(); i++) {
		if (i > 0 && nums[i] == nums[i - 1] && temp[i - 1] == false)
			continue;
		if (temp[i] == false) {
			temp[i] = true;
			v.push_back(nums[i]);
			dfs(v, temp, nums, count);
			v.pop_back();
			temp[i] = false;			
		}
	}
}
int main()
{
	int i, j, k, n, count = 0;
	cin >> n;
	vectornums(n, 0), v;
	for (i = 0; i < n; i++) {
		cin >> nums[i];
	}
	sort(nums.begin(), nums.end());
	vectortemp(n, false);
	dfs(v, temp, nums, count);
	cout << count << endl;

	system("pause");
	return 0;
}

7-3 找零钱***(回溯法)

收银员现有 n 张面值分别为 v1​,v2​,...,vn​ 的纸币。若找零金额为 m,则一共有多少种找零方法?

:0

输入格式:

n
v1​,v2​,...,vn​
m

输出格式:

若有解,则输出全部找零方案,每输出一种
若无解,则输出“None”

输入样例1:

6
3 1 4 3 2 7
9

输出样例1:

3 1 3 2
3 4 2
4 3 2
2 7

输入样例2:

5
5 3 4 6 7
2

输出样例2:

None

AC代码:

#include
using namespace std;
void dfs(vector> &res, vector &nums, vector &v, int m, int index) {
	if (m <= 0) {
		if (m == 0)
			res.push_back(v);
		return;
	}
	for (int i = index; i < nums.size(); i++) {
		v.push_back(nums[i]);
		dfs(res, nums, v, m - nums[i], i + 1);
		v.pop_back();
	}
}
int main()
{
	int i, j, n, m;
	cin >> n;
	vector>res;
	vectornums(n, 0), v;
	for (i = 0; i < n; i++) {
		cin >> nums[i];
	}
	cin >> m;
	dfs(res, nums, v, m, 0);
	if (res.empty())
		cout << "None" << endl;
	else {
		for (i = 0; i < res.size(); i++) {
			for (j = 0; j < res[i].size(); j++) {
				if (j == 0)
					cout << res[i][j];
				else
					cout << " " << res[i][j];
			}
			cout << endl;
		}		
	}

	system("pause");
	return 0;
}

7-4 整数拆分(回溯法)

将一个正整数n拆分成若干个正整数的和(至少两个数,n<=100)。

输入格式:

一个正整数n

输出格式:

若干行,每行一个等式(数与数之间要求非降序排列)。最后一行给出解的总个数

输入样例:

在这里给出一组输入。例如:

4

输出样例:

4=1+1+1+1
4=1+1+2
4=1+3
4=2+2
4

AC代码:

#include
using namespace std;
void dfs(vector> &res, vector &v, int n, int count, int index) {
	if (count >= n) {
		if (count == n && v.size() > 1)
			res.push_back(v);
		return;
	}
	for (int i = index; i <= n; i++) {
		v.push_back(i);
		dfs(res, v, n, count + i, i);
		v.pop_back();
	}
}
int main()
{
	int i, j, k, n;
	cin >> n;
	vector>res;
	vectorv;
	dfs(res, v, n, 0, 1);
	for (i = 0; i < res.size(); i++) {
		cout << n << "=";
		for (j = 0; j < res[i].size(); j++) {
			if (j == 0)
				cout << res[i][j];
			else
				cout << "+" << res[i][j];
		}
		cout << endl;
	}
	cout << res.size() << endl;

	system("pause");
	return 0;
}

7-5 数字三角形问题(动态规划)

给定一个由n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。

算法训练三(DFS、BFS、回溯)(含模板)(上)_第1张图片

 对于给定的由n行数字组成的数字三角形,计算从三角形的顶至底的路径经过的数字和的最大值。

输入格式:

输入数据的第1行是数字三角形的行数n,1≤n≤100。接下来n行是数字三角形各行中的数字。所有数字在0..99之间。

输出格式:

输出数据只有一个整数,表示计算出的最大值。

输入样例:

在这里给出一组输入。例如:

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出样例:

在这里给出相应的输出。例如:

30

AC代码:

#include
using namespace std;
int main()
{
	int i, j, k, n;
	cin >> n;
	vector>nums(n), dp(n);
	for (i = 0; i < n; i++) {
		nums[i].resize(i + 1);
		dp[i].resize(i + 1);
	}
	for (i = 0; i < n; i++) {
		for (j = 0; j < nums[i].size(); j++) {
			cin >> nums[i][j];
		}
	}
	for (i = nums.size() - 1, j = 0; j < nums[i].size(); j++) {
		dp[i][j] = nums[i][j];
	}
	for (i = nums.size() - 2; i >= 0; i--) {
		for(j = 0; j < nums[i].size(); j++) {
			dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + nums[i][j];
		}
	}
	cout << dp[0][0] << endl;

	system("pause");
	return 0;
}

7-6 幂集(回溯法)

有一个含n个数的数组a,所有元素均不相同,设计一个算法求其所有子集(幂集)。
例如:1 2 3的幂集{}、{3}、{2}、{2,3}、{1}、{1,3}、{1,2}、{1,2,3}

输入格式:

第一行输入元素个数n,再依次输入n个数。

输出格式:

输出子集数

输入样例:

3
1 2 3

输出样例:

8

AC代码:

#include
using namespace std;
void backtracking(vector &nums, int index, int &count) {
	count++;
	for (int i = index; i < nums.size(); i++) {
		backtracking(nums, i + 1, count);
	}
}
int main()
{
	int i, j, k, n, count = 0;
	cin >> n;
	vectornums(n, 0);
	for (i = 0; i < n; i++) {
		cin >> nums[i];
	}
	backtracking(nums, 0, count);
	cout << count << endl;

	system("pause");
	return 0;
}

7-7 子集和问题(回溯/深度优先搜索)

给定n个不同的正整数集合w=(w1,w2,…,wn)和一个正数W,要求找出w的子集s,使该子集中所有元素的和为W。

输入格式:

第一行输入n和W,第二行依次输入n个数。

输出格式:

每行输出一个符合要求的子集。

输入样例:

4 31
11 13 24 7

输出样例:

11 13 7 
24 7 

AC代码:

#include
using namespace std;
void dfs(vector> &res, vector &v, vector &nums, int n, int index) {
	if (n <= 0) {
		if (n == 0)
			res.push_back(v);
		return;
	}
	for (int i = index; i < nums.size(); i++) {
		v.push_back(nums[i]);
		dfs(res, v, nums, n - nums[i], i + 1);
		v.pop_back();
	}
}
int main()
{
	int i, j, k, n, m;
	cin >> m >> n;
	vectornums(m, 0), v;
	vector>res;
	for (i = 0; i < m; i++) {
		cin >> nums[i];
	}
	dfs(res, v, nums, n, 0);
	for (i = 0; i < res.size(); i++) {
		for (j = 0; j < res[i].size(); j++) {
			cout << res[i][j] << " ";
		}
		cout << endl;
	}

	system("pause");
	return 0;
}

7-8 工作分配问题(回溯/深度优先搜索)

设有n件工作分配给n个人。将工作i分配给第j个人所需的费用为cij 。 设计一个算法,对于给定的工作费用,为每一个人都分配1 件不同的工作,并使总费用达到最小。

输入格式:

输入数据的第一行有1 个正整数n (1≤n≤20)。接下来的n行,每行n个数,表示工作费用。        

输出格式:

将计算出的最小总费用输出到屏幕。

输入样例:

3
10 2 3
2 3 4
3 4 5

输出样例:

9

AC代码: 

#include
using namespace std;
void dfs(vector> &nums, vector &v, vector &temp, int count, int &res, int index) {
	if (count > res)
		return;
	if (v.size() == nums.size()) {
		res = min(res, count);
		return;
	}
	for (int i = index; i < nums.size(); i++) {
		for (int j = 0; j < nums[i].size(); j++) {
			if (temp[j]) {
				v.push_back(nums[i][j]);
				temp[j] = false;
				dfs(nums, v, temp, count + nums[i][j], res, i + 1);
				v.pop_back();
				temp[j] = true;
			}
		}
	}
}
int main()
{
	int i, j, k, n, count = 0, res = INT_MAX;
	cin >> n;
	vector>nums(n, vector(n, 0));
	vectortemp(n, true);
	vectorv;
	for (i = 0; i < n; i++) {
		for (j = 0; j < n; j++) {
			cin >> nums[i][j];
		}
	}
	dfs(nums, v, temp, count, res, 0);
	cout << res << endl;

	system("pause");
	return 0;
}

7-9 岛屿数量(深度优先搜索)

给你一个由 1(陆地)和 0(水)组成的n*m的二维网格,请你计算网格中岛屿的数量num。

岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。例如

0 0 0
0 1 0
0 0 1

此为两个岛屿

此外,你可以假设该网格的四条边均被水包围。1<=n,m<=100

输入格式:

第一行中给出网格长宽n,m
接下来的n行表示网格情况

输出格式:

岛屿个数num

输入样例:

4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1

输出样例:

3

AC代码:

#include
using namespace std;
vector>item = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}};
void dfs(vector> &nums, vector> &temp, int x, int y) {
	int new_x, new_y;
	for (auto & dir : item) {
		new_x = x + dir.first;
		new_y = y + dir.second;
		if (new_x >= 0 && new_x < nums.size() && new_y >= 0 && new_y < nums[0].size()) {
			if (temp[new_x][new_y] && nums[new_x][new_y]) {
				temp[new_x][new_y] = false;
				dfs(nums, temp, new_x, new_y);						
			}
		}			
	}
}
int main()
{
	int i, j, n, m, res = 0;
	cin >> m >> n;
	vector>nums(m, vector(n, 0));
	vector>temp(m, vector(n, true));
	for (i = 0; i < m; i++) {
		for (j = 0; j < n; j++) {
			cin >> nums[i][j];
		}
	}
	for (i = 0; i < m; i++) {
		for (j = 0; j < n; j++) {
			if (temp[i][j] && nums[i][j]) {
				dfs(nums, temp, i, j);
				res++;
			}
		}
	}
	cout << res << endl;


	system("pause");
	return 0;
}

7-10 小H喜欢睡觉(广度优先搜索)

小H十分喜欢睡觉,这天他起来一看,居然9.30了,而他答应了10点要到小W家去,小H想走知道小H到小W家的最短时间是多少,你能帮帮他吗。

地图是n * m的网格,每个单元是一个开放空间或建筑物(无法通过),小H的加在(1,1),小W 在(x,y)处,他只能上下左右移动,每一步需要1分钟。 输入数据可确保小W家可到达。

输入格式:

第一行具有两个正整数n,m,以空格(1 <= n,m <= 100)隔开,n为行,m为列
接下来是两个正整数x,y,用空格隔开(1 <= x <= n,1 <= y <= m)指示教学大楼的坐标
接下来是n行和m列的地图,0表示开放空间,1表示障碍物。

输出格式:

对于每个测试用例,输出一行包含整数的行,该行给出了小H到达小W家所需的最短时间(以分钟为单位)。

输入样例:

5 4
4 3
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1

输出样例:

7

AC代码:

#include
using namespace std;
vector>dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
typedef struct point {
    int x, y, step;
}point;
int bfs(vector> &nums, vector> &visit, int x, int y, int p, int q) {
    point start;
    start.x = x;
    start.y = y;
    start.step = 0;
    queueQ;
    Q.push(start);
    while (!Q.empty()) {
        if (Q.front().x == p && Q.front().y == q) {
            return Q.front().step;
        }
        int new_x, new_y;
        for (auto & dir : dirs) {
            new_x = Q.front().x + dir.first;
            new_y = Q.front().y + dir.second;
            if (new_x >= 0 && new_x < nums.size() && new_y >= 0 && new_y < nums[0].size()) {
                if (nums[new_x][new_y] == 0 && visit[new_x][new_y] == false) {
                    point temp;
                    temp.x = new_x;
                    temp.y = new_y;
                    temp.step = Q.front().step + 1;
                    Q.push(temp);
                    visit[new_x][new_y] = true;
                }
            }
        }
        Q.pop();
    }
    return -1;
}
int main()
{
    int i, j, k, n, m, res;
    int p, q;
    cin >> m >> n >> p >> q;
    vector>nums(m, vector(n, 0));
    vector>visit(m, vector(n, false));
    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) {
            cin >> nums[i][j];
        }
    }
    visit[0][0] = true;
    res = bfs(nums, visit, 0, 0, p - 1, q - 1);
    cout << res << endl;

    system("pause");
    return 0;
}

7-11 迷宫问题(深度优先搜索)

小明置身于一个迷宫,请你帮小明找出从起点到终点的最短路程。
小明只能向上下左右四个方向移动。

输入格式:

第一行是两个整数n和m (1≤ m, n ≤100),表示迷宫的长和宽。接下来是n行,每行m个数字,表示整个迷宫。空地格子用0表示,障碍物用1表示,小明所在起点用3表示,终点用4表示。

输出格式:

如果能够到达终点,输出一个整数,表示小明从起点到目的地所需的最短时间。如果不能到达终点,输出“unreachable”。

输入样例1:

5 5
1 0 1 1 1
1 0 4 1 0
1 0 0 1 0
0 0 0 1 0
1 0 3 0 1

输出样例1:

输入样例2: 

5 5
3 0 1 1 1
1 0 1 1 0
1 0 1 1 0
0 0 0 1 0
1 0 1 0 4

输出样例2:

unreachable 

AC代码:

#include
using namespace std;
vector>dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int res = INT_MAX;
void dfs(vector> &nums, vector> &visit, int x, int y, int p, int q, int step) {
    if (x == p && y == q) {
        res = min(res, step);
        return;
    }
    int new_x, new_y;
    for (auto & dir : dirs) {
        new_x = x + dir.first;
        new_y = y + dir.second;
        if (new_x >= 0 && new_x < nums.size() && new_y >= 0 && new_y < nums[0].size()) {
            if ((nums[new_x][new_y] == 4 || nums[new_x][new_y] == 0) && visit[new_x][new_y] == false) {                    
                visit[new_x][new_y] = true;
                dfs(nums, visit, new_x, new_y, p, q, step + 1);
                visit[new_x][new_y] = false;
            }
        }
    }
}
int main()
{
    int i, j, k, n, m, start_x, start_y, p, q;
    cin >> m >> n;
    vector>nums(m, vector(n, 0));
    vector>visit(m, vector(n, false));
    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) {
            cin >> nums[i][j];
            if (nums[i][j] == 3) {
                start_x = i;
                start_y = j;
            }
            if (nums[i][j] == 4) {
                p = i;
                q = j;
            }
        }
    }
    visit[start_x][start_y] = true;
    dfs(nums, visit, start_x, start_y, p, q, 0);
    if (res == INT_MAX)
        cout << "unreachable" << endl;
    else 
        cout << res << endl;

    system("pause");
    return 0;
}

7-12 走迷宫Ⅱ(广度优先搜索+优先队列)

一个迷宫由n行m列格子组成。有的格子是空地,可以走;有的格子处是障碍物,不能走;此外,有的格子处是一扇关闭的门,需要打开门后才能通过。小明准备从迷宫的某一格子(起点)走到另一个格子(终点),假定他只可以朝上、下、左、右四个方向移动,不能斜着走。每移动一个位置(格子)需要1分钟,打开一扇门需要额外的1分钟。给定迷宫和小明的起点和终点,请编写程序计算小明从起点到终点最短需要花费多少时间。

输入格式:

输入包含多组数据,每组数据第一行是两个整数n和m (1≤m,n≤100),表示迷宫的长和宽。接下来是n行,每行m个数字,表示整个迷宫。空地格子用0表示,障碍物用1表示,门用2表示,小明所在起点用3表示,终点用4表示。

输出格式:

对于每组数据,如果能够到达终点,输出一个整数,表示小明从起点到目的地所需的最短时间。如果不能到达终点,输出“unreachable”。

输入样例:

5 5
1 0 1 1 1
1 0 4 1 0
1 0 0 1 2
0 0 2 1 0
1 0 3 0 1
5 5
3 0 1 1 1
1 0 1 1 0
1 0 1 1 2
0 0 2 1 0
1 0 1 0 4

输出样例:

4
unreachable

AC代码:

#include
using namespace std;
vector>dirs ={{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
typedef struct point {
    int x, y, step;
}point;
struct cmp {
    bool operator() (point a, point b) {
        return a.step > b.step;
    }
};
string bfs(vector> &nums, vector> &visit, int start_x, int start_y, int p, int q) {
    point start;
    start.x = start_x;
    start.y = start_y;
    start.step = 0;
    priority_queue, cmp>Q;
    Q.push(start);
    while (!Q.empty()) {
        int x = Q.top().x;
        int y = Q.top().y;
        int step = Q.top().step;
        if (x == p && y == q) {
            return to_string(step);
        }
        int new_x, new_y;
        for (auto & dir : dirs) {
            new_x = x + dir.first;
            new_y = y + dir.second;
            if (new_x >= 0 && new_x < nums.size() && new_y >= 0 && new_y < nums[0].size()) {
                if ((nums[new_x][new_y] == 2 || nums[new_x][new_y] == 4 || nums[new_x][new_y] == 0) && visit[new_x][new_y] == false) {
                    point temp;
                    temp.x = new_x;
                    temp.y = new_y;
                    if (nums[new_x][new_y] == 2)
                        temp.step = step + 2;
                    else
                        temp.step = step + 1;
                    visit[new_x][new_y] = true;
                    Q.push(temp);
                }
            }
        }
        Q.pop();
    }
    return "unreachable";
}
int main()
{
    int i, j, n, m;
    vectorres;
    while (scanf("%d %d", &m, &n) != EOF && true) {
        int start_x, start_y, p, q;
        vector>nums(m, vector(n, 0));
        vector>visit(m, vector(n, false));
        for (i = 0; i < m; i++) {
            for (j = 0; j < n; j++) {
                cin >> nums[i][j];
                if (nums[i][j] == 3) {
                    start_x = i;
                    start_y = j;
                }
                if (nums[i][j] == 4) {
                    p = i;
                    q = j;
                }
            }
        }
        visit[start_x][start_y] = true;
        res.push_back(bfs(nums, visit, start_x, start_y, p, q));
    }
    for (i = 0; i < res.size(); i++) {
        cout << res[i] << endl;
    }



    system("pause");
    return 0;
}

7-14 h0252.拯救行动(广度优先搜索)

公主被恶人抓走,被关押在牢房的某个地方。牢房用N*M (N, M <= 200)的矩阵来表示。矩阵中的每项可以代表道路(@)、墙壁(#)、和守卫(x)。
英勇的骑士(r)决定孤身一人去拯救公主(a)。我们假设拯救成功的表示是“骑士到达了公主所在的位置”。由于在通往公主所在位置的道路中可能遇到守卫,骑士一旦遇到守卫,必须杀死守卫才能继续前进。
现假设骑士可以向上、下、左、右四个方向移动,每移动一个位置需要1个单位时间,杀死一个守卫需要花费额外的1个单位时间。同时假设骑士足够强壮,有能力杀死所有的守卫。

给定牢房矩阵,公主、骑士和守卫在矩阵中的位置,请你计算拯救行动成功需要花费最短时间。

输入格式:

第一行为一个整数S,表示输入的数据的组数(多组输入)
随后有S组数据,每组数据按如下格式输入

1、两个整数代表N和M, (N, M <= 200).

2、随后N行,每行有M个字符。"@"代表道路,"a"代表公主,"r"代表骑士,"x"代表守卫, "#"代表墙壁。

输出格式:

如果拯救行动成功,输出一个整数,表示行动的最短时间。
如果不可能成功,输出"Impossible"

输入样例:

2
7 8
#@#####@
#@a#@@r@
#@@#x@@@
@@#@@#@#
#@@@##@@
@#@@@@@@
@@@@@@@@ 
13 40
@x@@##x@#x@x#xxxx##@#x@x@@#x#@#x#@@x@#@x
xx###x@x#@@##xx@@@#@x@@#x@xxx@@#x@#x@@x@
#@x#@x#x#@@##@@x#@xx#xxx@@x##@@@#@x@@x@x
@##x@@@x#xx#@@#xxxx#@@x@x@#@x@@@x@#@#x@#
@#xxxxx##@@x##x@xxx@@#x@x####@@@x#x##@#@
#xxx#@#x##xxxx@@#xx@@@x@xxx#@#xxx@x#####
#x@xxxx#@x@@@@##@x#xx#xxx@#xx#@#####x#@x
xx##@#@x##x##x#@x#@a#xx@##@#@##xx@#@@x@x
x#x#@x@#x#@##@xrx@x#xxxx@##x##xx#@#x@xx@
#x@@#@###x##x@x#@@#@@x@x@@xx@@@@##@@x@@x
x#xx@x###@xxx#@#x#@@###@#@##@x#@x@#@@#@@
#@#x@x#x#x###@x@@xxx####x@x##@x####xx#@x
#x#@x#x######@@#x@#xxxx#xx@@@#xx#x#####@

输出样例:

13
7

AC代码:

#include
using namespace std;
vector>dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
typedef struct point {
    int x, y, step;
}point;
struct cmp {
    bool operator() (point a, point b) {
        return a.step > b.step;
    }
};
int bfs(vector &G, vector> &visit, int start_x, int start_y, int p, int q) {
    point start;
    start.x = start_x;
    start.y = start_y;
    start.step = 0;
    priority_queue, cmp>Q;
    Q.push(start);
    while (!Q.empty()) {
        int x = Q.top().x;
        int y = Q.top().y;
        int step = Q.top().step;
        if (x == p && y == q)
            return step;
        int new_x, new_y;
        for (auto & dir : dirs) {
            new_x = x + dir.first;
            new_y = y + dir.second;
            if (new_x >= 0 && new_x < G.size() && new_y >= 0 && new_y < G[0].length()) {
                if ((G[new_x][new_y] == '@' || G[new_x][new_y] == 'a' || G[new_x][new_y] == 'x') && visit[new_x][new_y] == false) {
                    point temp;
                    temp.x = new_x;
                    temp.y = new_y;
                    if (G[new_x][new_y] == 'x')
                        temp.step = step + 2;
                    else
                        temp.step = step + 1;
                    visit[new_x][new_y] = true;
                    Q.push(temp);
                }
            }
        }
        Q.pop();
    }
    return -1;
}
string solve() {
    int i, j, m, n, start_x, start_y, p, q, res;
    cin >> m >> n;
    vectorG(m);
    vector>visit(m, vector(n, false));
    for (i = 0; i < m; i++) {
        cin >> G[i];
        int index1, index2;
        index1 = G[i].find("r");
        index2 = G[i].find("a");
        if (index1 != -1) {
            start_x = i;
            start_y = index1;
        }
        if (index2 != -1) {
            p = i;
            q = index2;
        }
    }
    visit[start_x][start_y] = true;
    res = bfs(G, visit, start_x, start_y, p, q);
    if (res == -1)
        return "Impossible";
    return to_string(res);
}
int main()
{
    int i, j, k, n, t;
    cin >> t;
    vectorres;
    while (t--) {
        res.push_back(solve());
    }
    for (i = 0; i < res.size(); i++) {
        cout << res[i] << endl;
    }


    system("pause");
    return 0;
}

你可能感兴趣的:(PTA,算法,深度优先,宽度优先,c++)