-
在 3 X 3 的空格内,用1,2,…, 9 的9个数字填入9个空格内,使得每行数字组成的十进制数平方根为整数。试用一般图搜索搜索算法求解。
解:
-
定义状态空间:
设状态空间中的一点是3$\times$3矩阵
-
定义操作规则
(1)交换同一列相邻两行之间的元素
(2)交换同一行相邻两列之间的元素
-
实现搜索算法
用广度优先搜索算法求解
(1)将初始状态放入队列中
(2)当队列不为空时,从队列中取出一个状态
(3)对于当前状态,遍历其所有可能的状态转移,对于没有访问过的新状态,如果该状态是目标状态,则停止搜索并返回搜索结果;如果不是,则将新状态放入队列中。转(2)
(4)如果队列为空则搜索失败
若 ( i n t ) x ⋅ ( i n t ) x = x (int)\sqrt{x}\cdot(int)\sqrt{x}=x (int)x⋅(int)x=x,则 x \sqrt{x} x是整数
#include<bits/stdc++.h> using namespace std; #define N 3 typedef struct node{ string s; int x,y; }node; string start_s="123456789";//初始状态 string bfs(){ queue<node>q; map<string,bool>v; int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//状态转移,上下左右交换 node start; start.s=start_s; start.x=0,start.y=0; q.push(start); v[start.s]=true; while(!q.empty()){ node t=q.front(); q.pop(); for(int i=0;i<4;i++){ int nx=t.x+dir[i][0]; int ny=t.y+dir[i][1]; if(nx>=0&&nx<N&&ny>=0&&ny<N){ node next=t; swap(next.s[t.x*N+t.y],next.s[nx*N+ny]); next.x=nx; next.y=ny; if(!v[next.s]){ string s=next.s; int flag=1; for(int i=0;i<N;i++){ int dec=(s[i*N+0]-'0')*100+(s[i*N+1]-'0')*10+(s[i*N+2]-'0'); int psqrt=sqrt(dec); if(psqrt*psqrt!=dec){//目标状态的判断 flag=0; break; } } if(flag){ return s; } q.push(next); v[next.s]=true; } } } } return "unsolvable"; } int main(){ cout<<bfs()<<endl; }
解得 3 6 1 7 8 4 5 2 9 \begin{matrix}3&6&1\\7&8&4\\5&2&9\end{matrix} 375682149 。第一题多解,三行数字排列组合
-
-
分析宽度优先搜索和深度优先搜索的优缺点,举出他们的正例和反例。
宽度优先搜索
-
优点:若问题有解可以找到最优解
缺点:效率低,占用大量的存储空间
-
正例:求解最短路径
反例:八皇后问题
深度优先搜索
-
优点:节省大量的时间和空间
缺点:不一定能找到解或者找到的不是最优解,当搜索空间的深度很大时,可能会不能停机
-
正例:图的连通性检测;迷宫问题
反例:求解最短路径;
-
-
有一个农夫带一只狐狸、一只小羊和一个菜篮过河。假设农夫每次只能带一样东西过河,考虑安全,无农夫看管时,狐狸和小羊不能在一起,小羊和菜篮不能在一起。试设计求解该问题的状态空间,并画出状态空间图。
-
定义状态空间
用四元组(N,H,Y,C)表示农夫,狐狸,小羊和菜篮的状态,0表示在此岸,1表示在对岸。初始状态为(0,0,0,0),目标状态为(1,1,1,1)。当N为0时,H和Y不能同时为1,Y和C不能同时为1;当N为1时,H和Y不能同时为0,Y和C不能同时为0。
-
定义操作规则
go(x)表示农夫带着x到对岸,back(x)表示农夫带着x回到此岸。
-
状态空间图
-