DFS入門——素數環問題
阿新 • • 發佈:2020-07-05
題目出處:《資訊學奧賽一本通》例5.1。
題目描述
素數環:從 \(1\) 到 \(n(2 \le n \le 20)\) 這 \(n\) 個數擺成一個環,要求相鄰的兩個數的和是一個素數。
輸入格式
輸入包含一個整數 \(n(2 \le n \le 20)\) 。
輸出格式
按字典序從小到大的順序輸出所有排列方案,每個排列方案佔一行。每行的 \(n\) 個數之間由一個空格分隔。
樣例輸入
2
樣例輸出
1 2
2 1
問題分析
很明顯,這是一道可以用搜索解決的問題,我們可以採用“回溯”思想,使用深度優先搜尋解決這個問題。
我們用 ans[]
陣列來存放我們當前遍歷到的答案, ans[id]
用於表示當前排列的第 id 個數是什麼。所以我們可以開一個函式 void f(int id)
在第 id 個位置能放 i 當且僅當:
- \(ans[1]\) 到 \(ans[id-1]\) 都不等於 \(i\),即 \(i\) 之前沒有放過;
- 當 \(id \gt 1\) 時,滿足 \(ans[id-1]+ans[id]\) 是素數;
- 當 \(id = n\) 時,滿足 \(ans[1] + ans[n]\) 是素數。
這樣,我們遞迴地呼叫 f(id)
,當 id>n
時就是我們遞迴的邊界條件;一旦 id>n
就說明我找到了一種方案。
實現程式碼如下:
#include<bits/stdc++.h> using namespace std; int ans[22], n; bool isp(int a) { // 判斷a是否是素數 if (a < 2) return false; for (int i = 2; i * i <= a; i ++) if (a%i==0) return false; return true; } void output() { // 輸出一種排列方案 for (int i = 1; i <= n; i ++) cout << (i>1 ? " " : "") << ans[i]; cout << endl; } void f(int id) { // 搜尋函式,在第id個位置嘗試放上一個數 if (id > n) { // 邊界條件 if (isp(ans[1]+ans[n])) output(); return; } for (int i = 1; i <= n; i ++) { // 遍歷i = 1 to n ,看看第id個位置能否放i bool flag = true; if (id > 1 && !isp(ans[id-1]+i)) flag = false; if (flag) { for (int j = 1; j < id; j ++) if (ans[j] == i) { flag = false; break; } } if (flag) { ans[id] = i; f(id+1); } } } int main() { cin >> n; f(1); return 0; }