1. 程式人生 > 其它 >洛谷P1219 [USACO1.5]八皇后 Checker Challenge

洛谷P1219 [USACO1.5]八皇后 Checker Challenge

技術標籤:洛谷演算法dfs

拖了很久的八皇后問題,這還是簡化版的題目,簡單記錄一下,雖然能寫出來程式碼,但八皇后的問題解決的還是不夠清晰,沒有上一道三連擊題目清晰,下面貼出題目:
在這裡插入圖片描述

一個如下的 6×6的跳棋棋盤,有六個棋子被放置在棋盤上,使得每行、每列有且只有一個,每條對角線(包括兩條主對角線的所有平行線)上至多有一個棋子。

上面的佈局可以用序列2 4 6 1 3 5來描述,第i個數字表示第i行的相應位置有一個棋子,如下:

行號 1 2 3 4 5 6
列號 2 4 6 1 3 5

這只是棋子放置的一個解。請編一個程式找出所有棋子防止的解,並把它們以上面的序列方法輸出,解按字典順序排序,請輸出前面3個解。最後一行是解的總個數

解法思路:
1.首先考慮輸入和輸出,需要輸入棋盤的大小,在main函式裡面先進行
cin >> a;
確認好棋盤的大小。

2.其次考慮用什麼方法來實現這種輸出,典型的dfs問題,假設是6*6的棋盤,首先是利用回溯法先輸出6×6所有的序列,也就先輸出全排列,然後進行條件判斷,若條件滿足,則輸出滿足條件的序列即可。

下面貼上程式碼

int used[13] = { 0 };
int result[13] = { 0 };
int a,sum;

bool judge()
{
	for (int i = 0; i < a; i++)
	{
		for (int j = i +
1; j < a; j++) { if(abs(result[i] - result[j]) == abs(i - j)) return false; } } sum++; return true; } void dfs(int count) { if (count == a) { if (judge() && sum < 4) { for (int j = 0; j < a; j++) { cout << result[j] << " "; } cout <
< endl; } } for (int i = 0; i < a; i++) { if (used[i] == 0)//配合上剪枝使用 { int flag = true; for (int k = 0; k < count; k++) { if (abs(i + 1 - result[k]) == abs(k-count))flag = false; } if (flag == true) { used[i] = 1; result[count] = i + 1; dfs(count + 1); used[i] = 0; } } } } int main() { cin >> a; dfs(0); cout << sum; return 0; }

有個需要注意的小細節,因為陣列一開始就要定義好,所以直接設成最大的即可,這也是一種避免程式錯誤的方法,而該題目在判斷兩個皇后是否在同一斜線上是用,兩個皇后的行減行,列減列來進行判斷的。也就是

if(abs(result[i] - result[j]) == abs(i - j))

其中result是用來儲存皇后的位置的。

for (int i = 0; i < a; i++)
	{
		
		if (used[i] == 0)//配合上剪枝使用
		{
			int flag = true;
			for (int k = 0; k < count; k++)
			{
				if (abs(i + 1 - result[k]) == abs(k-count))flag = false;
			}
			if (flag == true)
			{
				used[i] = 1;
				result[count] = i + 1;
				dfs(count + 1);
				used[i] = 0;
			}
		}
	}

下面的是我的寫法,其中我的寫法是沒有剪枝的,所以我的複雜度很高,剪枝的方法還是不太熟悉,我需要特別的加強,看了半天程式碼也沒看明白,還是多做點回溯題來慢慢熟悉吧

for (int i = 0; i < a; i++)
	{
		if (used[i] == 0)
		{
			used[i] = 1;
			result[count] = i + 1;
			dfs(count + 1);
			used[i] = 0;
		}
	}