递归和回溯2(八皇后问题)

题干:
Nubia的苏丹没有子女,所以她决定,在她去世的时候,把她的国家分成k个不同的部分,每个部分将由在些测试中表现最好的人来继承,有可能某个人继承多个部分或者全部。为了确保最终只有智商最高的人成为她的继承者,苏丹设计了一个巧妙的测试。在一个喷泉飞溅和充满异香的大厅里,放着k个国际象棋棋盘。在棋盘中,每一个方格用从1到99范围内的数字进行编号,并提供8个宝石做的皇后棋子。每一个潜在的继承人的任务是将8个皇后放置在棋盘上,使得没有一个皇后可以攻击另一个皇后,并且对于棋盘上所选择的皇后所占据的方格,要求方格内的数字的总和要和苏丹选择的数字一样高。( 如果您不熟悉国际象棋的规则,这就是说,在棋盘上的每一行和每一列只能有一个皇后,并且在每条对角线上,最多只能有一个皇后。)
请您编写一个程序,输入棋盘的数量以及每个棋盘的详细情况,并确定在这些条件下每个棋盘可能的最高得分。(苏丹是一个好的棋争,也是一个优秀的数学家,她给出的数字是最高的。

输入
输入首先在行中给出棋盘的数量k,然后给出k个64个 数字组成的集合,每个集合由8行组成,每行8个数字,每个数字是小于100的正整数。棋盘的数量不会多于20。

输出
输出给出k个数字,表示你的k个得分,每个得分行,向右对齐,5个字符的宽度。
对8x8的棋盘来说,八皇后的放置方案有多种(共92种),在每种方案中放置8个皇后的位置不尽相同。由于在每个棋盘中,每一个方格用不同的数字进行编号,因此每种放置方案的得分也会不同。所以,在输入棋盘数据前,先离线计算出八皇后在棋盘上所有可能的放置方式。然后对每一个棋盘数据,计算每种放置方式中的得分,并获得其中的最高得分。

Sample input

1
1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48
48 50 51 52 53 54 55 56
57 58 59 60 61 62 63 64

Sample output
260

解题思想

首先可以确定是8✖️8的棋盘,所以可以把这满足每个“皇后”互不侵犯的可行的方法的8个位置通过一个数组都记下来。然后通过一个循环语句将每个方法获得的分数记录下来选择最高分输出。
func()中通过按行按列依次判断(!col[c]&&!left[ld]&&!right[rd])来确定是否可以将皇后放在这个位置,如果可以就做上记号。然后判断是否每行都有了皇后,如果有就记下8个皇后的列位置在P[x][y]数组中。然后继续溯洄,将上一个皇后所做的记号消除
回溯

在第一行第一列放第一个皇后,再在第二行从第一列开始尝试在哪里可以放第二个皇后,放完一轮后。在第一行看是否能在后面找到第二个位置也可以放第二个皇后,以此类推。

重点在于下面这两行,可以说回溯法就体现于此

func(r + 1);//递归下一行

col[c]=0; left[ld]=0; right[rd]=0;

在第一次确定r=0之后就深度递归func(1),在递归完毕之后,就会进行第二行的操作,将r=0第一次确定的皇后的位置清零,然后在第一行重新找一个可以放皇后的位置。r>0的时候也是,这样就可以很完美的完成一个递归回溯

#include <cstdio>
#include <vector>
using namespace std;
int P[1000][9];//方式i中第j行皇后的列位置
int tmp[8];//当前方式中第i行皇后的列位置为tmp[i]
int n= 0;//方式数初始化
bool col[8] = {0}, left[15] = {0}, right[15]= {0}; //所有 列和左右对角线未被选中

void func(int r)//从r行出发,递归计算所有方案中8皇后的位置
{
    if(r==8){//若搜索了所有行
        for(int i=0;i<8;i++) //记下当前方式中8个皇后的列位置
            P[n][i] = tmp[i];
        ++n;
        return;
    }
    for (int c=0;c<8; ++c) {//依次搜索r行的每一列
        int ld=(c-r)+ 7;//计算(r, c)的左右对角线序号
        int rd=c+r;
        if (!col[c]&&!left[ld] && !right[rd]){ //若第 c列和左右对角线未选中,则选中c列和左右对角线
            col[c] = 1; left[ld]= 1; right[rd]= 1;
            tmp[r]= c;//(r, c)置放皇后
            func(r + 1);//递归下一行.
            col[c]=0; left[ld]=0; right[rd]=0;
        }
    }
}

int main(){
    func(0);//从0行出发,自上而下递归计算所有方案中的8皇后位置
    int Case;
    int board[8][8];
    scanf("%d", &Case);//输入棋盘数
    while (Case--) {
        for (int i=0;i<8; ++i)//输入当前棋盘中每格的数字
            for (int j=0;j<8; ++j)
                scanf("%d", &board[i][j]);
        int ans= 0;
        for (int i=0;i<n; ++i) {//依次搜索每个方式
            int sum= 0;
            //第i个方式的得分初始化
            for (int j=0;j<8;++j) //搜索每
                sum += board[j][P[i][j]];
            if (sum>ans)
                ans=sum; //若 当前方式的得分目前最高,则调整棋盘最高得分
        }
        printf("%5d\n", ans);//输出当前棋盘的最高得分
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值