这道问题很精辟, 考察回溯的实现。
对于一个二维数组何如回溯的思想很有帮助。
由于我找到一个写得非常不错的文章, 我就不在这里自取欺辱了。
基于这道题的思想, 我自己对于二维数组的回溯实现有了一定的了解。
还是很有帮助的, 本章文件就相当于是一篇转发吧。
核心框架:
void Find_Queen(vector<vector<int>>& queen_pos, int rows, int* steps) {
//rows 控制 行数, 当rows == 8时,代表一个成功的结果
if (rows == 8) {
(*steps)++;
//Print(queen_pos); //打印八皇后的位置
return;
}
for (int cols = 0; cols < 8; cols++) {
if (Check(queen_pos, rows, cols)) {
//该位置为合格为止
queen_pos[rows][cols] = 1; //一个皇后存在该位置
Find_Queen(queen_pos, rows + 1, steps); //判断下一层皇后的位置
queen_pos[rows][cols] = 0; //回溯回来 - 该层位置不合适 - 换位置
}
}
}
传入的参数rows控制层数,函数里面的for循环中cols控制每一层的列数。
如果这一层有合适的插入位置, 就换一行处理
Find_Queen(queen_pos, rows + 1, steps);
如果这一层没有合适的位置,这里时候这个函数栈就会退出,返回到上一层调用栈, 由于rows没有到8, 所以回溯到上一层, 将这一层的位置清除掉,因为这个位置不合理。
queen_pos[rows][cols] = 0;
其实根据这个框架, 我们设计出二维数组的回溯问题, 随机组合问题等。
框架还是很重要的。
后面是我写得代码:
#include <iostream>
#include <vector>
using namespace std;
bool Check(const vector<vector<int>>& queen_pos, int row, int col) {
//行列判断
for (int i = 0; i < 8; i++) {
if (queen_pos[row][i] == 1 || queen_pos[i][col] == 1) {
return false;
}
}
//左上角判断
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (queen_pos[i][j] == 1) { return false; }
}
//右下角
for (int i = row + 1, j = col + 1; i < 8 && j < 8; i++, j++) {
if (queen_pos[i][j] == 1) { return false; }
}
//左下角
for (int i = row + 1, j = col - 1; i < 8 && j >= 0; i++, j--) {
if (queen_pos[i][j] == 1) { return false; }
}
//右上角
for (int i = row - 1, j = col + 1; i >= 0 && j < 8; i--, j++) {
if (queen_pos[i][j] == 1) { return false; }
}
return true;
}
void Print(const vector<vector<int>>& vec) {
for (const auto &vit : vec) {
for (const auto& vvit : vit) {
cout << vvit << ' ';
}
cout << endl;
}
cout << endl;
}
void Find_Queen(vector<vector<int>>& queen_pos, int rows, int* steps) {
//rows 控制 行数, 当rows == 8时,代表一个成功的结果
if (rows == 8) {
(*steps)++;
//Print(queen_pos); //打印八皇后的位置
return;
}
for (int cols = 0; cols < 8; cols++) {
if (Check(queen_pos, rows, cols)) {
//该位置为合格为止
queen_pos[rows][cols] = 1; //一个皇后存在该位置
Find_Queen(queen_pos, rows + 1, steps); //判断下一层皇后的位置
queen_pos[rows][cols] = 0; //回溯回来 - 该层位置不合适 - 换位置
}
}
}
int main() {
vector<vector<int>> queen_pos(8);
for (auto& vit : queen_pos) {
vit.resize(8, 0);
}
//0 -- 代表不存在, 1 代表存在
int rows = 0;
int steps = 0;
Find_Queen(queen_pos, rows, &steps);
cout << "八皇后共有:" << steps << endl;
return 0;
}
测试结果:
二、换乘问题
小明从起始站到终点站, 一共有4站, 每一站有三种选择, 分别为公交、火车、地铁。
1、每一站的公交、火车、地铁的价钱不一样。
2、你只能换乘2次, (上一站公交,下一站坐火车或地铁就是换乘一次)
公交、火车、地铁
第一站:1 6 7
第二站:4 2 3
第三站:5 3 4
第四站:4 7 7
实现代码:
#include <iostream>
#include <vector>
using namespace std;
int min_path = 0;
void FindMinPath(const vector<vector<int>>& vec, int rows, int flag, int &count, vector<int> &path) {
if (rows == 4) {
int sum = 0;
for (const auto& vit : path) {
sum += vit;
}
if (!min_path) { min_path = sum; }
else if (min_path > sum) { min_path = sum; }
return;
}
for (int cols = 0; cols < 3; cols++) {
if (rows != 0) {
//不是第一层, 存在换乘的问题
if (flag != cols) {
//换乘
count--; //换乘计数器--
if (count < 0) {
count++; //换乘次数已经用完, 因此直接空过, count++, 很容易忽略的问题
continue; //这一趟cols车不匹配, 换一乘判断
}
}
}
path.push_back(vec[rows][cols]); //插入
FindMinPath(vec, rows + 1, flag, count, path);
path.pop_back(); //回溯
if (flag != cols) {
//之前进来, 换乘计数器--, 因此回溯的时候, count++
count++;
}
}
}
int main() {
vector<vector<int>> vec(4);
for (auto& it : vec) {
it.resize(3);
}
int arr[4][3] = {
{1, 6, 7},
{4, 2, 3},
{5, 3, 4},
{4, 7 ,7}
};
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 3; j++) {
vec[i][j] = arr[i][j];
}
}
int rows = 0; //层数
int flag = 0; //标记上一层是什么车, 用于匹配是否换乘问题
int count = 2; //换成计数器
vector<int> path; //存储换乘的价值
FindMinPath(vec, rows, flag, count, path);
cout << "最小换乘2次时, 到达目的地最小价值为:" << min_path << endl;
return 0;
}
测试结果: