洛谷P1219 [USACO1.5]八皇后 Checker Challenge
阿新 • • 發佈:2021-02-13
拖了很久的八皇后問題,這還是簡化版的題目,簡單記錄一下,雖然能寫出來程式碼,但八皇后的問題解決的還是不夠清晰,沒有上一道三連擊題目清晰,下面貼出題目:
一個如下的 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;
}
}