1 8×8的棋盤上,選擇合適的位置放皇后,使得互相不攻擊(皇后可以攻擊所在點的該行、該列、該對角線),並且使得所在位置的數相加之和最大。
2 分析。
①學習到的:
a.
用一個行數組、左對角線數組、右對角線數組,分別表示某一行、某一條左對角線個、某一條右對角線是否被佔用。用於高效的處理,辨別是否在同一行、同一列、同一對角線的情況!
OR
b.
判斷先後下的點是否在同一行、同一列、同一對角線時,用這一行來判斷:
if(col[col_id]==col[j]||col_id+col[col_id]==j+col[j]||col_id-col[col_id]==j-col[j]){}
其中,col[x]=y,是指第x列選擇的皇后位置是第y行。不過這樣每次比較都得遍歷之前所存的數,不如上一種方法簡便一點。②錯誤思路:
剛開始想貪心,排序以後從最大的數開始,降序選擇,如果與已選的點不衝突,就加入這個點,但是這樣是錯的,因爲第一個點不一定非得選,同理,後面的點也是,可能把最佳組合反而屏蔽了。
然後普通的遞歸暴搜,用了下某個點則翻轉某個點的該行、該列、該對角線的棋子,進入下一個遞歸實例,出來這個遞歸實例時把之前翻轉的都反轉回來。這樣也是錯的,問題出在,如果翻轉該點的該行、該列、該對角線那麼有可能把不是這個子所影響的點的狀態給反轉了,那麼如果一定要翻轉狀態這種方法的話,那麼進入和退出某個遞推實例時,要記錄該層遞歸所翻轉的點,纔行。
3
a
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
int row[8]={0};// 該行是否被佔用,那麼索引是列
int leftx[15]={0};
int rightx[15]={0};
int board[8][8];
int p[1010][8];// 第一維是方法,第二維是第x列,值是所在第幾行
int cnt=0;
int column[8];
void Fun(int col){
if(col==8){
for(int i=0;i<8;i++){
//p[cnt][row[i]]=i;
p[cnt][i]=column[i];
}
cnt++;
return ;
}
for(int i=0;i<8;i++){// 搜索每一行
int ld=(i-col)+7;
int rd=(i+col);
if(!row[i]&&!leftx[ld]&&!rightx[rd]){
row[i]=leftx[ld]=rightx[rd]=1;//不能用row[i]=col,因爲可能有第零列,那麼!row[i]不妥
column[col]=i;
Fun(col+1);
row[i]=leftx[ld]=rightx[rd]=0;
}
}
}
int main()
{
///ini
Fun(0);
//cout<<cnt<<endl;
int k;
scanf("%d",&k);
while(k--){
///ini_scanf
int sum=0;
for(int i=0;i<8;i++)
for(int j=0;j<8;j++)
scanf("%d",&board[i][j]);
///compare
for(int i=0;i<cnt;i++){
int temp_sum=0;
for(int j=0;j<8;j++){ // 搜索每一列
temp_sum+=board[p[i][j]][j];
}
if(temp_sum>sum) sum=temp_sum;
}
printf("%5d\n",sum);
}
}
b
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
int board[10][10];
int col[10];
int flag=0;
int sum;
void Find(int col_id,int son_sum){
if(col_id==9){
if(son_sum>sum){
sum=son_sum;
}
return;
}
for(int i=1;i<=8;i++){
col[col_id]=i;
int temp=1;
for(int j=1;j<col_id;j++){
if(col[col_id]==col[j]||col_id+col[col_id]==j+col[j]||col_id-col[col_id]==j-col[j]){
temp=0;
break;
}
}
if(temp){
Find(col_id+1,son_sum+board[i][col_id]);
}
}
return ;
}
int main(){
int k;
scanf("%d",&k);
while(k--){
flag=0;
sum=0;
for(int i=1;i<=8;i++){
for(int j=1;j<=8;j++){
scanf("%d",&board[i][j]);
}
}
Find(1,0);
printf("%5d\n",sum);
}
}