1. 程式人生 > 其它 >棋盤挑戰(DFS,剪枝)

棋盤挑戰(DFS,剪枝)

技術標籤:題解演算法dfs剪枝

題目描述

給定一個 N×N 的棋盤,請你在上面放置 N個棋子,要求滿足:

  • 每行每列都恰好有一個棋子
  • 每條對角線上都最多隻能有一個棋子
    1   2   3   4   5   6
  -------------------------
1 |   | O |   |   |   |   |
  -------------------------
2 |   |   |   | O |   |   |
  -------------------------
3 |   |   |   |   |   | O |
  -------------------------
4 | O |   |   |   |   |   |
  -------------------------
5 |   |   | O |   |   |   |
  -------------------------
6 |   |   |   |   | O |   |
  -------------------------

上圖給出了當 N=6

時的一種解決方案,該方案可用序列 2 4 6 1 3 5 來描述,該序列按順序給出了從第一行到第六行,每一行擺放的棋子所在的列的位置。

請你編寫一個程式,給定一個 N×N的棋盤以及 N個棋子,請你找出所有滿足上述條件的棋子放置方案。

輸入格式

共一行,一個整數 N。

輸出格式

共四行,前三行每行輸出一個整數序列,用來描述一種可行放置方案,

序列中的第 i個數表示第 i行的棋子應該擺放的列的位置。

這三行描述的方案應該是整數序列字典序排在第一、第二、第三的方案。

第四行輸出一個整數,表示可行放置方案的總數。

資料範圍

6 ≤ N ≤ 13 6≤N≤13 6

N13

輸入樣例:

 6

輸出樣例:

2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4

C++ 程式碼

#include<iostream>
#include<algorithm>
using namespace std;

const int N=15;

int res=0, path[N]; // res 答案個數, path[] 具體的答案。
int n;
bool col[N],ldg[2*N],rdg[2*N]; // 分別為該點所在的 列,左對角線,右對角線。 

void dfs(int r)
{
     if(r>n)
	 {
res++; if(res<=3) { for(int i=1;i<=n;i++) printf("%d ",path[i]); printf("\n"); } return ; //可有可無 ,因為遍歷的行數 r 大於棋盤行數,終止 } for(int i = 1; i <= n; i++)//改行對應的每一列嘗試放棋子 { if(!col[i] && !ldg[i + r] && !rdg[n - i + r])//該點對應的列、左斜對角線、右斜對角線都沒有棋子,則可以放。 { path[r] = i;//放棋子 //相同對角線上的格子,i + r 相同, n - i + r 相同 col[i] = ldg[i + r] = rdg[n - i + r] = 1;//對應的列、左斜對角線、右斜對角線就棋子了 dfs(r + 1);//進行下一行 col[i] = ldg[i + r] = rdg[n - i + r] = 0;//狀態回滾 } } } int main() { cin>>n; dfs(1); cout<<res; return 0; }