UVa 167 - The Sultan's Successors, 八皇后问题

题目链接:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=108&page=show_problem&problem=103



题目类型: 回溯


原题:

 The Sultan of Nubia has no children, so she has decided that the country will be split into up to k separate parts on her death and each part will be inherited by whoever performs best at some test. It is possible for any individual to inherit more than one or indeed all of the portions. To ensure that only highly intelligent people eventually become her successors, the Sultan has devised an ingenious test. In a large hall filled with the splash of fountains and the delicate scent of incense have been placed k chessboards. Each chessboard has numbers in the range 1 to 99 written on each square and is supplied with 8 jewelled chess queens. The task facing each potential successor is to place the 8 queens on the chess board in such a way that no queen threatens another one, and so that the numbers on the squares thus selected sum to a number at least as high as one already chosen by the Sultan. (For those unfamiliar with the rules of chess, this implies that each row and column of the board contains exactly one queen, and each diagonal contains no more than one.)

Write a program that will read in the number and details of the chessboards and determine the highest scores possible for each board under these conditions. (You know that the Sultan is both a good chess player and a good mathematician and you suspect that her score is the best attainable.)


题目大意:

Sultan没有孩子,所以她决定做一个测试,选择一个继承人。 这个测试内容是, 有一个8*8的棋盘, 棋盘上的每个格子上都有

一个1~99的数字。然后,要放8个皇后上去,使它们不能同行,同列,同斜线,  并且求出8个放置位置上的数字之和最大

的值。


分析与总结:

赤裸裸的八皇后问题了,只是增加了个求和的步骤。

首先, 可以得出这8个皇后一定是在不同行上的, 然后,还可以进一步判断每一行上的列坐标都是不同的,即恰好每行每列

放置一个皇后。这样,就只需要再判断是否斜线上有冲突即可。

接下来就好办了,我们可以开一个数组loc[9] = {0,1,2,3,4,5,6,7},   数组下标对应行,数组元素的值对应该行的列。 我们只需要

枚举loc的全排列, 然后写一个judge函数来判断这个排列方案是否符合八皇后规则即可,如果符合的话,就计算棋盘上对应的

值的和,更新维护一个全局的最大值即可。

0~7的排列一共有8!=40320个, 而枚举两不会超过这个。


1. 暴力枚举法

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define MOD 
using namespace std;
int map[8][8];
int loc[8];

bool judge(){
    for(int i=1; i<8; ++i){
        for(int j=0; j<i; ++j){
            if(i-j==loc[i]-loc[j] || i-j==loc[j]-loc[i])
                return false;
        }
    }
    return true;
}

int main(){
#ifdef LOCAL
    freopen("input.txt","r",stdin);
#endif
    int T;
    scanf("%d",&T);
    while(T--){
        for(int i=0; i<8; ++i)
            for(int j=0; j<8; ++j)
                scanf("%d", &map[i][j]);

        for(int i=0; i<8; ++i)
            loc[i] = i;
        int maxVal = -1;
         
        do{
            if(judge()){
                int sum=0;
                for(int i=0; i<8; ++i)
                    sum += map[i][loc[i]];
                if(sum > maxVal) maxVal = sum;
            }
        }while(next_permutation(loc, loc+8));
        
        printf("%5d\n", maxVal);
    }
    return 0;
}

2.回溯法

回溯法的基本思路和上面的也很像,递归逐行进行放置, 放置时要先进行判断,是否和之前的有冲突即可。


#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
int map[8][8], loc[8], maxVal;
bool vis[8];

inline bool judge(int cur, int col){
    for(int i=0; i<cur; ++i){
        if(loc[i]==col || cur-i==loc[i]-col || cur-i==col-loc[i])
            return false;
    }
    return true;
}

void search(int cur, int sum){
    for(int i=0; i<8; ++i)if(!vis[i] && judge(cur,i)){
        vis[i] = true;
        loc[cur] = i;
        search(cur+1, sum+map[cur][i]);
        vis[i] = false;
    }
    if(cur==8 && sum>maxVal) maxVal = sum;
}

int main(){
#ifdef LOCAL
    freopen("input.txt","r",stdin);
#endif
    int T;
    scanf("%d",&T);
    while(T--){
        for(int i=0; i<8; ++i)
            for(int j=0; j<8; ++j)
                scanf("%d", &map[i][j]);

        maxVal = -1;
        memset(vis, 0, sizeof(vis));
        search(0, 0);
        
        printf("%5d\n", maxVal);
    }
    return 0;
}

——  生命的意义,在于赋予它意义。

 

          
     原创  http://blog.csdn.net/shuangde800  , By   D_Double  (转载请标明)






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值