UVA 167 八皇后·(1) 遞歸、暴搜

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);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章