c++回溯法編程彙總

回溯算法的定義:回溯算法也叫試探法,它是一種系統地搜索問題的解的方法。回溯算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。

  •     遞歸函數的開頭寫好中止條件,或者跳出條件,滿足條件纔將當前結果加入總結果中,或者不滿足讓函數return,防止重複遍歷
  •     已經經過的地點不在經過(已經搜索過的解空間不再重複搜索)
  •     遍歷過當前節點後,爲了回溯到上一步,要去掉已經加入到結果list中的當前節點。

目錄

一、矩陣中的路徑

1.1 題幹

二、矩陣中的遞增路徑

1.1 題幹

1.2 思路及代碼

三、不同路徑

3.1 題幹

3.2 分析

3.2 障礙物的不同路徑

3.3 思路及解法

四、N皇后問題

4.1 題幹

4.2 分析

五、數獨解

5.1 題幹

5.2 分析

六、推箱子

6.1 題幹

6.2 思路及程序


一、矩陣中的路徑

OJ:https://www.nowcoder.com/practice/c61c6999eecb4b8f88a98f66b273a3cc?tpId=13&tqId=11218&tPage=4&rp=4&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

1.1 題幹

例如 a b c e s f c s a d e e 矩陣中包含一條字符串"bccced"的路徑,但是矩陣中不包含"abcb"路徑,判斷是否存在,存在返回true,不存在返回false

1.2 思路

遍歷,進行匹配

  • 依次從每個位置出發,與匹配的路徑進行對比
  • 設置bool矩陣,尺寸大小與矩陣相同,已經經過的位置,則將bool中的值設置爲true,防止重複經過
  • 不想被改變的量,我們可以加上const修飾,以免不小心將其改變,如果改變const的變量,編譯器會報錯
  • 經過的矩陣以對於moving中的reached矩陣,不要加引用&,因爲這樣,每調用一次,會重新傳遞參數給相應的函數。
  • 此代碼在每次進入下次函數遞歸的時候加判斷,可能會導致代碼不夠精簡。如果直接可以在每次函數開始之前加判斷,可能能夠精簡代碼。因此,我們可以重新編寫函數。
#include<iostream>
#include<vector>
#include<cstdio>
#include<stdio.h>
#include<algorithm>
using namespace std;

class Solution {
public:
	bool hasPath(char* matrix, int rows, int cols, const char* str)
	{
		bool exist = false;
		int length = strlen(str);
		for (int idx_r = 0; idx_r < rows; idx_r++){
			for (int idx_c = 0; idx_c < cols; idx_c++){
				vector<bool> reached(rows*cols, false);
				exist = exist || (moving(matrix, idx_r, idx_c, rows, cols, str, reached, 0, length));
				if (exist)return true;
			}
		}
		return exist;
	}
	bool moving(const char* matrix, int cur_r, int cur_c, int rows, int cols,
		const char* str, vector<bool> reached, int str_loc, const int length){
		int location = cur_r*cols + cur_c;
		if (matrix[location] != str[str_loc])return false;//不相等則此路徑不存在
		else if (str_loc == length - 1){//餘下情況是可能存在路徑的情況
			//如果已經到了str的結尾,則路徑存在,return true
			return true;
		}
		//如果沒有到str結尾,則接着往下比較
		reached[location] = true;//關於reached矩陣,相當於每個往函數裏面都複製了一份,千萬不要用引用&,而要直接傳入
		bool exist = false;
		// right
		int right = cur_r*cols + cur_c + 1;
		if (cur_c + 1 < cols && !reached[right]){
			exist = exist || (moving(matrix, cur_r, cur_c + 1, rows, cols, str, reached, str_loc + 1, length));
		}
		// left
		int left = cur_r*cols + cur_c - 1;
		if (cur_c - 1 >= 0 && !reached[left]){
			exist = exist || (moving(matrix, cur_r, cur_c - 1, rows, cols, str, reached, str_loc + 1, length));
		}
		// up
		int up = (cur_r + 1)*cols + cur_c;
		if (cur_r + 1 < rows && !reached[up]){
			exist = exist || (moving(matrix, cur_r + 1, cur_c, rows, cols, str, reached, str_loc + 1, length));
		}
		//down
		int down = (cur_r - 1)*cols + cur_c;
		if (cur_r - 1 >= 0 && !reached[down]){
			exist = exist || (moving(matrix, cur_r - 1, cur_c, rows, cols, str, reached, str_loc + 1, length));
		}
		return exist;
	}
};

int main(){
	char *matrix = "abcesfcsadee";
	int rows = 3; int cols = 4;
	char *str1 = "bcced";  // true
	char *str2 = "abcb";  // false
	Solution s1;
	cout << s1.hasPath(matrix, rows, cols, str1) << endl;//true
	cout << s1.hasPath(matrix, rows, cols, str2) << endl;//true
	int end; cin >> end;
	return 0;
}

下面的代碼,先判斷,後遞歸,從代碼量上已經下降很多:

class Solution {
public:
	bool hasPath(char* matrix, int rows, int cols, const char* str)
	{
		bool exist = false;
		int length = strlen(str);
		for (int idx_r = 0; idx_r < rows; idx_r++){
			for (int idx_c = 0; idx_c < cols; idx_c++){
				vector<bool> reached(rows*cols, false);
				exist = exist || (moving(matrix, idx_r, idx_c, rows, cols, str, reached, 0, length));
				if (exist)return true;
			}
		}
		return exist;
	}
	bool moving(const char* matrix, int cur_r, int cur_c, int rows, int cols,
		const char* str, vector<bool> reached, int str_loc, const int length){
		int location = cur_r*cols + cur_c;
		if (cur_r<0 || cur_r >= rows || cur_c<0 || cur_c >= cols || reached[location] == true || matrix[location] != str[str_loc])return false;//不相等則此路徑不存在
		else if (str_loc == length - 1){//餘下情況是可能存在路徑的情況
			//如果已經到了str的結尾,則路徑存在,return true
			return true;
		}
		//如果沒有到str結尾,則接着往下比較
		reached[location] = true;//關於reached矩陣,相當於每個往函數裏面都複製了一份,千萬不要用引用&,而要直接傳入
		bool exist = false;
		// right
		exist = exist || (moving(matrix, cur_r, cur_c + 1, rows, cols, str, reached, str_loc + 1, length));
		// left
		exist = exist || (moving(matrix, cur_r, cur_c - 1, rows, cols, str, reached, str_loc + 1, length));
		// up
		exist = exist || (moving(matrix, cur_r + 1, cur_c, rows, cols, str, reached, str_loc + 1, length));
		//down
		exist = exist || (moving(matrix, cur_r - 1, cur_c, rows, cols, str, reached, str_loc + 1, length));
		return exist;
	}
};

 

二、矩陣中的遞增路徑

1.1 題幹

2019.9.7 依圖面試,當時面試的時候,list不小心弄成了&list,導致運行失敗。但是思路基本沒有錯誤。事後馬上就編寫出來了。

輸出最長遞減序列路徑以及路徑中的最後一個元素的位置:

給定一個矩陣,輸入

{ 1, 2, 3 },
{ 4, 5, 6 },
{ 9, 0, 8 }

輸出其最長遞減的子字符串的長度和第一個元素的位置

輸出2,2 5最長路徑的起點是8,其位置爲2,2

1.2 思路及代碼

  • 用list存當前路徑,如果存不下,則list中止,存入全局變量all_list之中。
  • 如果存得下,就繼續往下遞歸
#include <iostream>
#include<vector>
using namespace std;

int row;
int col;
void moving(int loc_r, int loc_c, vector<vector<int>> matrix, vector<int> list, vector<vector<int>>&all_list){
	list.push_back(matrix[loc_r][loc_c]);

	bool exist = false;
	// down
	if ((loc_r + 1< ::row) && matrix[loc_r + 1][loc_c]>list[list.size() - 1]){
		exist = true;
		moving(loc_r + 1, loc_c, matrix, list, all_list);
	}
	//up
	if (loc_r - 1 >= 0 && matrix[loc_r - 1][loc_c]>list[list.size() - 1]){
		exist = true;
		moving(loc_r - 1, loc_c, matrix, list, all_list);
	}
	//left
	if (loc_c - 1 >= 0 && matrix[loc_r][loc_c - 1]>list[list.size() - 1]){
		exist = true;
		moving(loc_r, loc_c - 1, matrix, list, all_list);
	}
	//right 
	if (loc_c + 1< ::col && matrix[loc_r][loc_c + 1]>list[list.size() - 1]){
		exist = true;
		moving(loc_r, loc_c + 1, matrix, list, all_list);
	}
	if (!exist){
		list.push_back(loc_r);
		list.push_back(loc_c);
		all_list.push_back(list);
		//list.clear();
		return;
	}
}
int main() {
	vector<vector<int>>matrix{ { 1, 2, 3 }, { 4, 5, 6 }, { 9, 0, 8 } };
	row = matrix.size();
	col = matrix[0].size();
	vector<int> list;
	vector<vector<int>>all_list;
	for (int idx = 0; idx<row; idx++){
		for (int idx_c = 0; idx_c<col; idx_c++){
			moving(idx, idx_c, matrix, list, all_list);
		}
	}
	int max_len = -2;
	int last_row, last_col;
	for (auto item : all_list){
		cout << "max_len " << max_len << " size-2 " << item.size() - 2 << endl;
		int length = item.size() - 1;
		if (length > max_len){
			cout << "in if max_len " << max_len << " size-2 " << item.size() - 2 << endl;
			max_len = item.size() - 2;
			last_row = item[item.size() - 2];
			last_col = item[item.size() - 1];
		}
	}
	cout << last_row << ',' << last_col << " " << max_len << endl;
	int end; cin >> end;
	return 0;
}

三、不同路徑

3.1 題幹

LeetCode 980,OJ:

https://leetcode-cn.com/problems/unique-paths-iii/

在二維網格 grid 上,有 4 種類型的方格:

  •     1 表示起始方格。且只有一個起始方格。
  •     2 表示結束方格,且只有一個結束方格。
  •     0 表示我們可以走過的空方格。
  •     -1 表示我們無法跨越的障礙。

返回在四個方向(上、下、左、右)上行走時,從起始方格到結束方格的不同路徑的數目,每一個無障礙方格都要通過一次。即012的方格,必須且有且只有通過一次,-1的方格不能經過。

輸入:[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]

輸出:2

3.2 分析

又是典型的走迷宮問題。需要回歸的是走法的方法數目。

設置遞歸函數:

  • 設置已經經過的路徑用vector<vector<bool>>passed來實現
  • 如果-1,則return false;表明此路徑失敗,不存在
  • 如果是2,則表示運行到終點,如果每個0的點都經過了,則此路徑運行成功
#include<iostream>
#include<vector>
#include<cstdio>
#include<stdio.h>
#include<string>
#include<algorithm>
using namespace std;

class Solution {
public:
	int uniquePathsIII(vector<vector<int>>& grid) {
		int row = grid.size();
		if (row < 1)return 0;
		int col = grid[0].size();
		if (col < 1)return 0;
		//設置經過的位置的矩陣,經過則設爲passed
		vector<bool>passed_col(col, false);
		vector<vector<bool>>passed(row, passed_col);
		int methods = 0;
		for (int r = 0; r < row; r++){
			for (int c = 0; c < col; c++){
				if (grid[r][c] == 1){
					moving(row, col, grid, methods, r, c, passed);
				}
			}
		}
		return methods;
	}
	void moving(const int row, const int col, const vector<vector<int>>& grid,
		int &methods, int cur_r, int cur_c, vector<vector<bool>>passed){
		//走出格子之外,或者碰壁-1,或者走回頭路,則直接返回
		if (cur_r >= row || cur_r<0 || cur_c >= col || cur_c < 0 || grid[cur_r][cur_c] == -1 || passed[cur_r][cur_c]){
			return;
		}
		//成功走到終點2,且每個都經過了一次,經過的方法數目+1
		if (grid[cur_r][cur_c] == 2){
			//判斷是否經過的0或者1均經過,如果不是的話,則直接返回
			for (int r = 0; r < row; r++){
				for (int c = 0; c < col; c++){
					if (grid[r][c] == 0 || grid[r][c] == 1){
						if (!passed[r][c]){
							return;
						}
					}
				}
			}
			methods++;
			return;
		}
		// 如果其他情況,則繼續往下走
		if (grid[cur_r][cur_c] == 0 || grid[cur_r][cur_c] == 1){
			passed[cur_r][cur_c] = true;
			moving(row, col, grid, methods, cur_r + 1, cur_c, passed);
			moving(row, col, grid, methods, cur_r - 1, cur_c, passed);
			moving(row, col, grid, methods, cur_r, cur_c + 1, passed);
			moving(row, col, grid, methods, cur_r, cur_c - 1, passed);
		}
	}
};

int main(){

	vector<vector<int>> grid = { { 1, 0, 0, 0 },
	{ 0, 0, 0, 0 }, { 0, 0, 2, -1 } };// out 2
	vector<vector<int>> grid2 = { { 1, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 2 } };//out 4

	Solution s1;
	cout << s1.uniquePathsIII(grid) << endl;
	cout << s1.uniquePathsIII(grid2) << endl;

	int end; cin >> end;
	return 0;
}

3.2 障礙物的不同路徑

機器人希望從左上角到右下角,中間有障礙物。只能向左或者向下走,問有多少種走法?障礙物在矩陣中用1表示。

輸入[
  [0,0,0],
  [0,1,0],
  [0,0,0]]
輸出: 2

3.3 思路及解法

動態規劃方法

  • 很簡單,可以看作動態規劃,當前路徑爲左邊和上邊的路徑數
  • 如果當前爲1,障礙物,則路徑必不存在,則當前方法數目爲0
#include<iostream>
#include<vector>
#include<cstdio>
#include<stdio.h>
#include<string>
#include<algorithm>
using namespace std;

class Solution {
public:
	int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
		int row = obstacleGrid.size();
		if (row < 1)return 0;
		int col = obstacleGrid[0].size();
		if (col < 1)return 0;
		if (obstacleGrid[0][0] == 1)return 0;
		vector<unsigned long long int> col_methods(col, 0);
		vector<vector<unsigned long long int>>methods(row, col_methods);
		//到每一點的方法數目
		methods[0][0] = 1;
		//第一列,行的方法數目
		for (int idx = 1; idx < row; idx++){
			if (obstacleGrid[idx][0] == 1)methods[idx][0] = 0;
			else{
				methods[idx][0] = methods[idx - 1][0];
			}
		}
		for (int idx = 1; idx < col; idx++){
			if (obstacleGrid[0][idx] == 1)methods[0][idx] = 0;
			else{
				methods[0][idx] = methods[0][idx - 1];
			}
		}
		//每一個位置的方法數目是其左邊和上邊方法數的和
		for (int r = 1; r < row; r++){
			for (int c = 1; c < col; c++){
				if (obstacleGrid[r][c] == 1)methods[r][c] = 0;
				else{
					methods[r][c] += methods[r - 1][c] + methods[r][c - 1];
				}
			}
		}
		return methods[row - 1][col - 1];
	}
};

int main(){
	vector<vector<int>> grid = { { 0, 0, 0 },
	{ 0, 1, 0 }, { 0, 0, 0 } };// out 2
	Solution s1;
	cout << s1.uniquePathsWithObstacles(grid) << endl;
	int end; cin >> end;
	return 0;
}

四、N皇后問題

N皇后問題,Leetcode 51

OJ:https://leetcode-cn.com/problems/n-queens/

4.1 題幹

n 皇后問題研究的是如何將 n 個皇后放置在 n×n 的棋盤上,並且使皇后彼此之間不能相互攻擊。即這N個皇后不能同行同列同斜列。

輸入,棋盤,輸出放置的方法:
輸入: 4
輸出: [
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]]

4.2 分析

看作回溯法的問題:

  • 每行找到一個元素,放置之後,如果可以的話往下一個行放
  • 每行放入的時候,如果滿足條件,才往下一行放,不滿足則不放
  • 到結尾的時候,滿足條件則對最終結果push_back
  • 用每行的列位置來存儲,則能簡化存儲與運算。最後再恢復出來

代碼:

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

class Solution {
public:
	vector<vector<string>> solveNQueens(int n) {
		vector<vector<string>> result_matrix;
		if (n < 1)return result_matrix;
		vector<int> col_loc(n);// col[idx=row],一共n列
		vector<vector<int>>result; //用於存儲所有滿足條件的位置的集合
		find_location(n, 0, col_loc, result);

		if (result.empty())return result_matrix;
		else{//根據行列值恢復出皇后矩陣
			for (auto item : result){
				string each_row(n, '.');
				vector<string> matrix(n, each_row);//空矩陣
				for (int idx = 0; idx < n; idx++){//填入皇后
					matrix[idx][item[idx]] = 'Q';
				}
				result_matrix.push_back(matrix);
			}
		}
		return result_matrix;
	}
	//判斷當前row位置的元素是否與其他元素(<row)衝突
	bool judge_correct(const int n, const int row, const vector<int> col_loc){
		for (int idx = 0; idx < row; idx++){
			if (col_loc[idx] == col_loc[row])return false;//列不能相等
			if (idx + col_loc[idx] == row + col_loc[row])return false;//右上、左下不衝突
			if (idx - col_loc[idx] == row - col_loc[row])return false;//左上,右下不衝突
		}
		return true;
	}
	//給當前row位置元素判斷
	void find_location(const int n, int row, vector<int> col_loc, vector<vector<int>> &result){
		//如果已經到最後一行,可以加入則將元素加入之後返回
		if (row == n - 1){
			for (int idx = 0; idx < n; idx++){
				col_loc[row] = idx;
				if (judge_correct(n, row, col_loc)){
					result.push_back(col_loc);
				}
			}
			return;
		}
		//如果沒有到最後一行,則加入元素之後進行遞歸
		for (int idx = 0; idx < n; idx++){
			col_loc[row] = idx;
			if (judge_correct(n, row, col_loc)){
				find_location(n, row + 1, col_loc, result);
			}
		}
	}
};

int main(){
	Solution s1;
	vector<vector<string>> result_matrix = s1.solveNQueens(4);

	if (result_matrix.empty())cout << "Empty!" << endl;
	else{
		for (auto matrix : result_matrix){
			cout << endl << "matrix:" << endl;
			for (auto row_string : matrix){
				cout << row_string << endl;
			}
		}
	}


	int end; cin >> end;
	return 0;
}

五、數獨解

OJ:Leetcode 37

https://leetcode-cn.com/problems/sudoku-solver/

5.1 題幹

將數獨填完:

  •     數字 1-9 在每一行只能出現一次。
  •     數字 1-9 在每一列只能出現一次。
  •     數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。

輸入:
53..7....
6..195...
.98....6.
8...6...3
4..8.3..1
7...2...6
.6....28.
...419..5
....8..79
輸出
534678912
672195348
198342567
859761423
426853791
713924856
961537284
287419635
345286179

5.2 分析

  • 針對每一個元素進行填充,如果符合規矩,則繼續向下遞歸填充下一個未填充的元素
  • 當前元素填充試過所有的,即進行return
  • 運行超時,電腦上運行發現程序沒有錯誤,但是運行較慢,下面代碼是暴力窮舉法,顯然不行,必須加入約束條件進行判斷
#include<iostream>
#include<vector>
#include<cstdio>
#include<set>
#include<string>
#include<algorithm>
using namespace std;

class Solution {
public:
	void solveSudoku(vector<vector<char>>& board) {
		vector<vector<char>>result;
		find_sudoku(board, result);
		board = result;
	}
	//判斷新加入元素是否符合
	bool num_match(const vector<vector<char>> board, const int row, const int col){
		for (int idx = 0; idx < 9; idx++){
			//行不同
			if (idx != col){
				if (board[row][col] == board[row][idx])return false;
			}
			//列不同
			if (idx != row){
				if (board[row][col] == board[idx][col])return false;
			}
		}
		//每個九宮格內不同
		int grid_row = row / 3; int grid_col = col / 3;
		for (int r = 3 * grid_row; r < 3 * grid_row + 3; r++){
			for (int c = 3 * grid_col; c < 3 * grid_col + 3; c++){
				if (r != row || c != col){
					if (board[r][c] == board[row][col])return false;
				}

			}
		}
		return true;
	}
	void find_sudoku(vector<vector<char>> board, vector<vector<char>> &result){
		int row = 0; int col = 0;
		for (row = 0; row < 9; row++){
			for (col = 0; col < 9; col++){
				//遍歷每一行每一列,找到新的未填充的元素
				if (board[row][col] == '.'){
					//給每個元素填入相應的值,判斷能否合規
					for (int idx = 1; idx <= 9; idx++){
						board[row][col] = '0' + idx;
						//填充值恰當則繼續往下填充
						if (num_match(board, row, col)){
							find_sudoku(board, result);
						}
					}
					return;//需要在當前元素填充結束之後,結束當前遍歷。
				}
			}
		}
		if (row == 9 && col == 9)result = board;
	}
};

int main(){
	vector<char>each_row(9);
	vector<vector<char>> board(9, each_row);

	/*
	53..7....
	6..195...
	.98....6.
	8...6...3
	4..8.3..1
	7...2...6
	.6....28.
	...419..5
	....8..79
	*/
	for (int row = 0; row < 9; row++){
		for (int col = 0; col < 9; col++){
			cin >> board[row][col];
		}
	}

	Solution s1;
	s1.solveSudoku(board);
	//輸出矩陣
	for (int row = 0; row < 9; row++){
		for (int col = 0; col < 9; col++){
			cout << board[row][col];
		}
		cout << endl;
	}

	int end; cin >> end;
	return 0;
}

六、推箱子

6.1 題幹

體規則就是在一個N*M的地圖上,有1個玩家、1個箱子、1個目的地以及若干障礙,其餘是空地。玩家可以往上下左右4個方向移動,但是不能移動出地圖或者移動到障礙裏去。如果往這個方向移動推到了箱子,箱子也會按這個方向移動一格,當然,箱子也不能被推出地圖或推到障礙裏。當箱子被推到目的地以後,遊戲目標達成。現在告訴你遊戲開始是初始的地圖佈局,請你求出玩家最少需要移動多少步才能夠將遊戲目標達成。

輸入描述:

  •     每個測試輸入包含1個測試用例
  •     第一行輸入兩個數字N,M表示地圖的大小。其中0<N,M<=8。
  •     接下來有N行,每行包含M個字符表示該行地圖。其中 . 表示空地、X表示玩家、*表示箱子、#表示障礙、@表示目的地。
  •     每個地圖必定包含1個玩家、1個箱子、1個目的地。

輸出描述:

輸出一個數字表示玩家最少需要移動多少步才能將遊戲目標達成。當無論如何達成不了的時候,輸出-1。

4 4
....
..*@
....
.X..
輸出3

...#..
......
#*##..
..##.#
..X...
.@#...
輸出11

1 3
X*@
輸出1

6.2 思路及程序

思路:

  • 一個記錄當前人和箱子位置的變量
  • 如果溢出或者撞牆,則return
  • 如果沒有溢出或者沒有撞牆,則繼續往下
  • 人和箱子挨着且與方向一致則推箱子,不一致人自己走
  • 運算複雜度較高,運行一次耗時較長
#include <iostream>
#include <vector>
#include <algorithm>
#include<string>

using namespace std;
int row, col;
int moves = -1;
void moving(int r, int c, int br, int bc, int current_moves,
	const vector<vector<char>> matrix, vector<vector<bool>>p_reach){
	
	// 運行失敗
	if (r < 0 || r >= row || c < 0 || c >= col || p_reach[r][c] == true || matrix [r][c]=='#'||
		br < 0 || br >= row || bc < 0 || bc >= col || matrix[br][bc]=='#'){
		//cout << "fail" << endl;
		return;
	}

	//// 輸出當前矩陣狀態
	//cout << endl;
	//for (int idx = 0; idx < row; idx++){
	//	for (int cdx = 0; cdx < col; cdx++){
	//		if (idx == r && cdx == c)cout << 'X';
	//		else if (idx == br && cdx == bc)cout << '*';
	//		else cout << matrix[idx][cdx];
	//	}
	//	cout << endl;
	//}

	//運行成功
	if (matrix[br][bc] == '@'){
		if (moves == -1)moves = current_moves;
		else if (current_moves < moves){
			//cout << "success,current:"<<current_moves<<"moves:"<<moves << endl;
			moves = current_moves;
		}
		return;
	}
	current_moves++;
	p_reach[r][c] = true; 
	//推或者走
	// down
	if (r + 1 == br && c == bc)moving(r + 1, c, br + 1, bc, current_moves, matrix, p_reach);
	else moving(r + 1, c, br, bc, current_moves, matrix, p_reach);
	//up
	if (r - 1 == br && c == bc)moving(r - 1, c, br - 1, bc, current_moves, matrix, p_reach);
	else moving(r - 1, c, br, bc, current_moves, matrix, p_reach);
	//right
	if (r  == br && c+1 == bc)moving(r , c+1, br , bc+1, current_moves, matrix, p_reach);
	else moving(r , c+1, br, bc, current_moves, matrix, p_reach);
	//left
	if (r == br && c - 1 == bc)moving(r, c - 1, br, bc- 1, current_moves, matrix, p_reach);
	else moving(r, c - 1, br, bc, current_moves, matrix, p_reach);
	return;
}

int main(){
	cin >> row >> col;
	vector<char> each_row(col);
	vector<vector<char>>matrix(row, each_row);
	for (int r = 0; r < row; r++){
		for (int c = 0; c < col; c++){
			cin >> matrix[r][c];
		}
	}
	vector<bool> r_reach(col, false);
	vector<vector<bool>>p_reach(row, r_reach);
	int pr, pc, br, bc;
	for (int r = 0; r < row; r++){
		for (int c = 0; c < col; c++){
			if (matrix[r][c] == 'X'){
				pr = r; pc = c;
			}
			if (matrix[r][c] == '*'){
				br = r; bc = c;
			}
		}
	}
	moving(pr, pc, br, bc, 0, matrix,p_reach);

	cout << ::moves << endl;

	int end; cin >> end;
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章