参考博客:http://www.cnblogs.com/gaoteng/archive/2012/04/11/2442692.html
题目链接:http://lx.lanqiao.cn/problem.page?gpid=T374
问题描述 规则同8皇后问题,但是棋盘上每格都有一个数字,要求八皇后所在格子数字之和最大。 输入格式 一个8*8的棋盘。 输出格式 所能得到的最大数字和 样例输入 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 样例输出 260 数据规模和约定 棋盘上的数字范围0~99
思考:解答本题首先得了解什么是8皇后(为此我百度了一下)。 8皇后:
八皇后问题是一个以国际象棋为背景的问题,
如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。
所以首先要做的就是先解决8皇后问题,即是8个皇后共有多少种不同的放法,解决此问题后,再在定义一个8*8的数组,将数据存起来然后比大小即可。
然后思考如何处理8皇后问题:第一行有8种放法,而每一种放法下一行又对应了8种放法(当然这里先不考虑此问题的规则)……
那么层层放下去就会得到一个满8叉树,那么此问题就可以用树形的思想去解决,用深度优先递归算法来对每一层进行遍历(这时候按照规则排除不满足的情况)。
那么接下来思考如何找出不满足的情况: 问题要求8个皇后不能同时位于同列、同行、同斜线。这里我定义x数组,下标i表示行,值x[i] 表示在皇后放在 i 行所在的那一列,那么只要每一个皇后所处的 i 和 x[i],不同即可满足不同行、不同列。至于同斜线,观察可知位于同一斜线的两个位置如i 行 j行 满足等式abs(i-j) == abs(x[i] – x[j] )。故次8皇后的 问题可以解决了。
然后在每一个位置上放一个数比较相加即可,但是需要注意的一点是在每一下一次递归结束后应该把递归之前加的那个数减去然后在进行下一次递归。
代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#define M 8+1
using namespace std;
int x[M]; //下标表示皇后所在的行,x[i]表示皇后所在的列
int sum,maxNum;
int ar[9][9]; //代表每个点的数值
int max(int n1, int n2){
if(n1>n2) return n1;
return n2;
}
bool isPlace(int k){
//不能是同行或者同列 或者同对角线
for(int i=1; i<k; ++i){
if(abs(i-k) == abs(x[k]-x[i]) || abs( x[i] == x[k] ) )
return false;
}
return true;
}
void onTrace(int t){
if(t>8){
maxNum = max(maxNum, sum);
}else{
for(int i=1; i<=8; ++i){ //col
x[t]=i;
if(isPlace(t)){
sum+=ar[t][i];
onTrace(t+1);
//递归完之后就会进行下一列递归,所以应该把前一列的那个数去掉
sum-=ar[t][i]; //important!! here, error more than once
}
}
}
}
int main()
{
for(int i=1; i<=8; ++i){
for(int j=1; j<= 8; ++j){
scanf("%d", &ar[i][j]);
}
}
maxNum=-1;
onTrace(1); //
printf("%d\n", maxNum);
return 0;
}