一、问题描述
在 n*n
的棋盘上填入 1, 2, 3, ……, n*n
共 n*n
个数,使得任意两个相邻数的和为素数(相邻指上下左右,而不是斜对角),当问题无解时,给出“无解”。
二、题解
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
class Solution {
private:
vector<vector<vector<int>>> result; // 结果集合
vector<int> prime_num; // 素数数组
public:
vector<vector<vector<int>>> getAdjacentPrimeNumbers(int n) {
vector<vector<int>> each_case(n, vector<int>(n, 0));
auto records = init(n);
backtracking(each_case, records, n, 0, 0);
return result;
}
private:
/**
* 回溯函数
* @param each_case 用于模拟棋盘中的数值填充并记录每一种符合条件的情况
* @param records 用于记录 1 ~ n*n 中的每个候选值的使用情况
* @param n 棋盘大小
* @param row 行游标
* @param col 列游标
*/
void backtracking(vector<vector<int>> &each_case, vector<bool> records, int n, int row, int col) {
/* 递归终止条件判断 */
if (row == n) {
result.emplace_back(each_case);
return;
}
/* 循环测试每一个值的可能性 */
for (int i: prime_num) {
int num;
/* 确定本轮循环要填充的值 num */
if (row > 0) {
/* 根据上边的数值确定本位置数值 */
num = i - each_case.at(row - 1).at(col);
/* 不合理或无意义的计算结果 */
if (num <= 0) {
continue;
} else if (num > records.size()) {
break;
}
/* num 已经被使用过了 */
if (records.at(num - 1)) {
continue;
}
if (col > 0) {
/* 检查 num 与左边的数值和是否为素数 */
if (!isPrime(num + each_case.at(row).at(col - 1))) {
continue;
}
}
} else if (col > 0) {
/* 根据左边的数值确定本位置数值 */
num = i - each_case.at(row).at(col - 1);
/* 不合理或无意义的计算结果 */
if (num <= 0) {
continue;
} else if (num > records.size()) {
break;
}
/* num 已经被使用过了 */
if (records.at(num - 1)) {
continue;
}
if (row > 0) {
/* 检查 num 与上边的数值和是否为素数 */
if (!isPrime(num + each_case.at(row - 1).at(col))) {
continue;
}
}
} else {
/* 无需顾及周围值的约束 */
static int begin_num = 1;
num = begin_num;
begin_num++;
}
/* 处理当前位置 */
each_case.at(row).at(col) = num;
records.at(num - 1) = true;
/* 递归 */
if (col == n - 1) {
backtracking(each_case, records, n, row + 1, 0); // 处理下一行
} else {
backtracking(each_case, records, n, row, col + 1); // 处理下一列
}
/* 回溯 */
each_case.at(row).at(col) = 0;
records.at(num - 1) = false;
}
}
/**
* 用于验证值是否为素数
* @param x
* @return
*/
static bool isPrime(int x) {
for (int i = 2; i <= sqrt(x); i++) {
if (x % i == 0) {
return false;
}
}
return true;
}
/**
* 初始化素数数组及记录数组
* @param n
* @return
*/
vector<bool> init(int n) {
for (int i = 2; i < 2 * n * n; i++) {
bool tag = true;
for (int j = 2; j <= sqrt(i); j++) {
if (i % j == 0) {
tag = false;
break;
}
}
if (tag) {
prime_num.emplace_back(i);
}
}
vector<bool> records(n * n, false);
return records;
}
};
int main() {
Solution solution;
auto res = solution.getAdjacentPrimeNumbers(2);
if (res.empty()) {
cout << "无解" << endl;
} else {
for (const auto &i: res) {
for (const auto &j: i) {
for (const auto &k: j) {
printf("%2d ", k);
}
cout << endl;
}
cout << endl;
}
}
return 0;
}
三、运行结果
atreus@MacBook-Pro % clang++ adjacentPrimeNumbers.cpp -o main -std=c++11
atreus@MacBook-Pro % ./main
1 2
4 3
1 4
2 3
2 1
3 4
2 3
1 4
3 2
4 1
3 4
2 1
4 1
3 2
4 3
1 2
atreus@MacBook-Pro %