1. 程式人生 > >基礎練習 2n皇后問題 dfs

基礎練習 2n皇后問題 dfs

問題描述   給定一個n*n的棋盤,棋盤中有一些位置不能放皇后。現在要向棋盤中放入n個黑皇后和n個白皇后,使任意的兩個黑皇后都不在同一行、同一列或同一條對角線上,任意的兩個白皇后都不在同一行、同一列或同一條對角線上。問總共有多少种放法?n小於等於8。 輸入格式   輸入的第一行為一個整數n,表示棋盤的大小。
  接下來n行,每行n個0或1的整數,如果一個整數為1,表示對應的位置可以放皇后,如果一個整數為0,表示對應的位置不可以放皇后。 輸出格式   輸出一個整數,表示總共有多少种放法。 樣例輸入 4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1 樣例輸出 2 樣例輸入 4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1 樣例輸出

0

思路:可以先看這個 N皇后問題 然後在做這個 這個是升級版的皇后問題。

這裡我們要我們填充兩種皇后,那麼我們先一種一種來填,填完這種然後在填另一種.

方法和N皇后問題差不多,我們開兩個陣列  a[i] b[i] i為皇后所在的行 a[i] b[i] 所存值為換行所在的列 

 ,然後列舉可行的列,並用陣列記錄位置,然後判斷是否存在同一列同一對角線的情況(因為這裡我們是按行填充的所以肯定滿足了不在同一行的情況).利用等腰直角三角形來判斷是否在對角線上 即 abs(a[step]-a[j])==step-j?  step-j 為行 a[step]-a[j]為列 判斷同一列很好判斷

填充完一種皇后後再填另一種(注意0 1是否能放皇后)

判斷兩個皇后是否重疊 : 填第二種皇后時 需要判斷 b[step]==a[step]? 前面說了 陣列儲存的是該皇后所在行的列下標 那麼當二者相等時行下標一樣列下標相同那麼就在同一位置了 此時不可以.

#include<bits/stdc++.h>
using namespace std;
int n,sum;
int s[10][10];
int a[11],b[11];
void dfs2(int step)
{
	int flag;
	if(step==n+1)
	{
		sum++;
		return ;
	}
	for(int i=1;i<=n;i++)
	{
		if(s[step][i]==0||a[step]==i)//判斷是否重疊
		continue;
		flag=1;
		b[step]=i;
		for(int j=1;j<=step-1;j++)
		{
			if(b[step]==b[j]||abs(b[step]-b[j])==step-j)
			{
				flag=0;
				break;
			}
		}
		if(flag)//如果不滿足要繼續找
		{
			dfs2(step+1);
		}
	}
	return ;
}
void dfs1(int step)
{
	int flag;
	if(step==n+1)
	{
		dfs2(1);
		return ;
	}
	for(int i=1;i<=n;i++)
	{
		flag=1;
		if(s[step][i]==0)
		continue;
		a[step]=i;//這裡的值不需要復位的因為如果當前不滿足題意下一次繼續查詢時會覆蓋的。
		for(int j=1;j<=step-1;j++)
		{
			if(a[step]==a[j]||abs(a[step]-a[j])==step-j)
			{
				flag=0;
				break;
			}
		}
		if(flag)
			{
				dfs1(step+1);
			}
	}
	return ;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	  scanf("%d",&s[i][j]);
	  sum=0;
	  dfs1(1);
	  printf("%d\n",sum);
	  return 0;
}