棋盘挑战(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 6N13

输入样例:

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

猜你喜欢

转载自blog.csdn.net/weixin_46339668/article/details/112979077