我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛
注:本系列文章实为算法题分析,所涉及到的兔兔场景为虚构题材,博君一笑,请勿当真。如有雷同,实属巧合~
不知不觉,兔子突突又长大了一点,也开始去认识一些新的小伙伴。
摸石子游戏
任务描述
这天,它在河边看到一大一小两只兔子在玩什么游戏,它凑过去观察了一会儿,终于了解了游戏规则:
- 现场有一些小石子。
- 每一回合,这两只兔子轮流拿掉 1-3 块石子。
- 拿掉最后一块石头的兔子就是赢家。
但是突突感到很奇怪的是,每一次大兔子都说要首先拿,但每一次最后的赢家却总是大兔子,这可把小兔子给气哭了。而大兔子说:“诶嘿~这可不赖我!说明是你运气不好,你看,你每次明明可以选择拿1-3个石子呀,你有这么多次改变的机会,都没能顺利拿到最后一块石头,是你的问题哟~”。
小兔子嚷嚷着它也要先抽,大兔子就以扎手为由随手扔掉了几颗石子,或者补新石子或者不补,几番回合下来,大兔子依然全胜。
突突觉得事情没那么简单。果然,它通过观察分析,最终发现了大兔子的秘密,并且告诉了小兔子。
大兔子嘿嘿一笑,说是和自己妹妹开玩笑的。说完,它从背后拿出了一根胡萝卜送给小兔子以示补偿。
你知道突突发现的秘密是什么吗? 欢迎把答案打在评论区上!答案文末也会揭晓~
N皇后问题
突突的机敏让大兔子对它刮目相看,于是它打算给突突出一道难题。富有挑战精神的的突突爽快地答应了下来。
难题描述
大兔子把突突领到家里的象棋桌前,给它讲起了规则:
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将
n
个皇后放置在n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。给定一个整数
n
,返回所有不同的 n皇后问题 的解决方案。每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中
'Q'
和'.'
分别代表了皇后和空位
突突以前哪里见过这种场面?一下就被唬住了。
它尝试了n=4的情况,得出了有两种解法的结论。但当它想尝试5的时候,感觉自己头都要大了。
显然,突突现在还不适合解决这种问题。精通编程的你能帮帮它,借助计算机的算力解决这个问题吗?
游戏谜底
摸石子游戏
这个游戏又叫“Nim游戏”。只要掌握技巧,从一开始就已经注定了结局。
当石子数不是4的倍数的时候,首先抽的人总能赢。
用代码表示就是:return n%4!=0;
至于为什么,可以用以下这段话概括:
面对4的整数倍的人永远无法翻身,你拿N根对手就会拿4-N根,保证每回合共减4根,你永远面对4倍数,直到4. 相反,如果最开始不是4倍数,你可以拿掉刚好剩下4倍数根,让对方永远面对4倍数。——力扣评论区
而这也是大兔子不在首抽后想要换掉石子数量的原因。
N皇后问题
这是经典的回溯问题。以下是基于集合的回溯解法:(代码中有较详细注释)
class Solution {
private:
vector<vector<string>> result;
vector<string> path;
private:
// 检测以[row,col]位置的 两条对角线以及列上 是否存在皇后 (剪枝: 只需要检测 [0,row) 行的部分)
bool check(int row, int col, int n) {
for (int i = 0; i < row; ++i) {
int col45 = row + col - i; // 当前[row,col]位置的 45°对角线(正对角线)上的 所有坐标的纵坐标。 (这条对角线上的 row+col相等)
int col135 = i - (row - col); // 当前[row,col]位置的 135°对角线(反对角线)上的 所有坐标的纵坐标。(这条对角线上的 row-col相等)
if (path[i][col] == 'Q' || (col45 >= 0 && col45 < n && path[i][col45] == 'Q') || (col135 >= 0 && col135 < n && path[i][col135] == 'Q')) {
return false;
}
}
return true;
}
// 第row行的皇后放在何处
void dfs(int n, int row) {
if (row == n) { // 说明最后一行也放完了,从而得到一种结果
result.push_back(path);
return;
}
// 每行只能放一个,但可能在该行任意列
for (int col = 0; col < n; ++col) {
if (check(row, col, n)) { // 检测当前位置是否可以放皇后
path[row][col] = 'Q'; // 放
dfs(n, row + 1); // 再下一行放
path[row][col] = '.'; // 收 (回溯)
}
}
}
public:
vector<vector<string>> solveNQueens(int n) {
path = vector<string>(n, string(n, '.')); // 初始化 (都没放)
dfs(n, 0); // 从第0行开始放
return result;
}
};
本期内容到这里就结束啦~感谢你能看到这里!欲知后事如何,请听下回分解!