繼續來水一道題。。。
一、 實驗目的
- 加深對求解一個3 * 3方格兩兩相鄰爲質數求解算法的理解;
- 通過本次試驗掌握將算法轉換爲上機操作;
- 加深對深度優先搜索思想的理解,理解回溯原理即實現過程,並利用其解決生活中的問題。
二、實驗內容
任務:求解填字遊戲問題
在3*3個方格的方陣中填入數字1-10的某9個數字,每個方格填-一個整
數,使所有相鄰兩個方格內的兩個整數之和爲素數。編寫一個程序,求出所有
滿足這個要求的數字的填法。
三、實驗原理
首先本題就是求一個3 * 3方格中填十個數1-10,使得兩兩相鄰的之和爲質數,求解所有方案!
本題適合採用深度優先搜索DFS來求解:
- 從(0,0)開始向右搜索,搜到(3,0)結束
- 搜索時記錄那些點被用過,下一個點一定是沒有被用過的點,使用vis數組標記
- 退出條件:搜索到 x == 3時,即此時九個點都已經填了一遍值,輸出填入的九個值
- 改點是否可以填入,是否合法:使用check函數來檢查一下,由於是從左向右開始填起,所以相鄰元素只需要考慮上和下兩個方向,check函數加上判斷邊界的條件即可。
- 若該點合法,則填入該點,否則繼續循環找一個可選點。
- 判斷邊界:即不能超出 3 * 3 的範圍,到了最右邊要進行換行,否則橫座標直接++即可!具體實現:
if(y == 2) dfs(x + 1, 0); else dfs(x, y + 1);
- 最後取消標記,回溯上一個點,找下一種選擇情況。
四、程序代碼
說明: 深度優先搜索一遍即可。
函數說明:
- Isprime():用來判斷是否是質數
- Check():用來判斷當前位置放入一個值是否合法,即相鄰是否爲質數。
- Dfs():用來深度優先搜索一遍九個位置,並將符合條件的進行打印
代碼如下:
#include <iostream>
using namespace std;
int a[3][3], count;
bool vis[10];
bool isprime(int n)
{
for(int i = 2; i * i <= n; i++){
if(n % i == 0) return false;
}
return true;
}
bool check(int x, int y, int k)
{
// 上
if(x - 1 >= 0 && !isprime(a[x - 1][y] + k)) return false;
// 左
if(y - 1 >= 0 && !isprime(a[x][y - 1] + k)) return false;
return true;
}
void dfs(int x, int y)
{
if(x == 3){
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
cout << a[i][j] << " ";
}
cout << endl;
}
cout << endl;
count ++;
return;
}
for(int i = 1; i <= 10; i++){
if(!vis[i] && check(x, y, i)){
a[x][y] = i; vis[i] = true;
if(y == 2) dfs(x + 1, 0);
else dfs(x, y + 1);
a[x][y] = 0; vis[i] = false;
}
}
}
int main()
{
dfs(0, 0);
cout << "Total: " << count << endl;
return 0;
}
五、實驗結果
說明:總共有128種方案,截圖太多,保留第一張和最後一張!
測試一:
測試二:
六、分析總結
- 通過本次實驗掌握了求解3 * 3 保證相鄰爲質數填空的問題,瞭解了一些相關算法的實現及求解原理。
- 瞭解並掌握了深度優先搜索算法和回溯算法的實現原理及求解過程,加深了對該算法原理的理解和實現。
- 明白了回溯的過程及遞歸解決問題的一些優點,要將所學所掌握的優秀解決問題算法用到現實世界中來解決一些不好用人力解決的問題。