n后问题(回溯)

n后问题(回溯)

1.问题描述
在nxn格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线 上的棋子。n后问题等价于,在nxn格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。

2.构建解空间:

①怎么表示解:(x1,x2,x3……,xn) xi表示(i,xi)即第i个皇后放在第i行的第xi列。

②显约束:xi=1,2,……n

③隐约束:

  • 不在同一列:xi ≠ xj 
  • 不在同一正、反对角线:| xi - xj | ≠ | i - j |
  • i ≠ j ,  i,j = 1,2,……n

④解空间树:排列树。(每一分量的取值范围随着位置变化而变化,比如前一个分量有n中选择,后一个分量有n-1种选择)

1

如果用蛮力处理,即在8x8的棋盘上安排出8个位置,这有C_{64}^{8} 种安排法,逐一测试,即要检查将近4.4*10^{109}个8元组用回溯法最多只要作8!次检查,即最多只要查40320个8元组实际上还少得多,对于8皇后问题,不受限结点是8皇后解空间树的结点总数的2.34%。因此,用回溯法处理比用枚举法好得多!
 

3.代码:

递归回溯:

class Queen {
    friend int nQueen(int);
    private:
    bool Place(int k);
    void Backtrack(int t);
    int n;//皇后个数
    int *x;//当前解
    1ong sum;//当前已找到的可行方案数
};
bool Queen::Place(int k) {
    for (int j=1; j < k; j++)
        if ((abs(k-j) == abs(x[j]-x[k]))||(x[j] == x[k]))
            return false;
    return true;
}

这里用的是变种的子集树。其实用排列树的框架性能更好。 

void Queen: :Backtrack(int t) {
    if(t>n)
        sum++;
    else {
        for (int i=1; i<= n; i++) {
            x[t] = i;
        if (Place(t))
            Backtrack(t+1);
        }
    }
}
int nQueen(int n) {
    Queen X;//初始化X
    X.n = n;
    X.sum = e;
    int *p = new int [n+1];
    for (int 1=0; i <= n; i++){
        p[i] = 0;
        X.x= p;
    }
    X. Backtrack(1);
    delete[] p;
    return x.sum;
}

迭代回溯

void:Queen Backtrack(){
    x[1]=0;
    int k=1;
    while(k>0){
        x[k]++;
        while(x[k]<=n&&!place(k))//第k个分量选取合适的值
            x[k]++;
        if(x[k]<=n){//选取到了合适的值
            if(k==n){//到达叶子节点,方案数++
               sum++;
            }
            else{
                k++;//下一个分量
                x[k]=0;//初始化为0
            }
        }
        else//找不到合适的取值,回溯
            k--;
    }
    
}

排列树法:

void Queen::Backtrack(int t) {
    if(t>n)
        sum++;
    else {
        for (int i=t; i<= n; i++) {
            swap(x[t],x[i]);
            if (Place(t))
                Backtrack(t+1);
            swap(x[t],x[i]);
        }
    }
}

 

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hnu哈哈

请接受直女的么么哒????

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值