class Solution {
  public:
    int Nqueen(int n) {
        int count = 0;
        vector<int> position(n, 0); // position[i]表示第i行皇后放在第几列
        backtrack(0, n, position, count);
        return count;
    }

  private:
    void backtrack(int row, int n, vector<int>& position, int& count) {
        if (row == n) {
            // 所有行都放置完毕,找到一个解
            count++;
            return;
        }

        // 尝试在当前行的每一列放置皇后
        for (int col = 0; col < n; col++) {
            if (isValid(row, col, position)) {
                position[row] = col; // 放置皇后
                backtrack(row + 1, n, position, count); // 递归到下一行
                // 回溯:不需要显式重置position[row],因为会被覆盖
            }
        }
    }

    bool isValid(int row, int col, const vector<int>& position) {
        // 检查当前位置(row, col)是否合法
        for (int i = 0; i < row; i++) {
            // 检查是否在同一列
            if (position[i] == col) {
                return false;
            }
            // 检查是否在同一对角线:行差 == 列差
            if (abs(row - i) == abs(col - position[i])) {
                return false;
            }
        }
        return true;
    }
};

// 共同的回溯框架
void backtrack(当前状态) {
    if (到达终止条件) {
        记录解;
        return;
    }
    
    for (所有可能的选择) {
        if (选择合法) {
            做选择;
            backtrack(下一状态);
            撤销选择;
        }
    }
}

全排列和N皇后问题回溯都是自动的,递归调用返回时都发生回溯;制权都返回到上一层的for循环;会继续尝试下一个选择
撤销操作不是"不自动回溯"的证据,而是不同状态管理策略的体现。回溯的核心机制——递归返回后继续循环——在两种算法中是完全相同的!
撤销选择更深层的设计原则:
何时需要显式撤销?
状态会累积或影响后续决策
状态改变是添加式的而非替换式的
状态需要在回溯后恢复到之前的确切值

何时可以依赖覆盖?
每个决策点的状态是独立的
状态存储是固定大小的数组
新的选择会自然覆盖旧的选择