DFS
枚举所有可以到达目标状态的路径,递归或者借助栈来实现,对一个传入状态,遍历它的子状态,对每一个都进行判断,若合法,则递归搜索这一子状态,直到达成目标条件或者状态不合法,则回溯到父亲节点,搜索下一个子状态。
递归:
bool judge(参数列表){ //参数不合法或越界时返回false 否则返回true } void dfs(传入状态){ if(达成目标条件){ 输出信息或者修改信息; return; } for(遍历传入状态的所有子状态){ if(judge(子状态)){ 传入状态加标记; dfs(子状态); 传入状态取消标记//回溯 } } }
洛谷P1605 迷宫
int n,m,t,fx,fy,vis[10][10],arr[10][10],dict[4][2] = {{-1,0},{1,0},{0,-1},{0,1}},ans = 0; bool judge(int i,int j){ if(i < 1 || i > n || j < 1 || j > m) return false;//出边界 if(arr[i][j] || vis[i][j]) return false;//不合法 障碍 return true; } void dfs(int i,int j){ if(i == fx && j == fy){ ++ans; return; } for(int k=0;k<4;k++){ int x,y; x = i+dict[k][0]; y = j+dict[k][1]; if(judge(x,y)){//判断下一个点是否合法 ++vis[i][j];//走过的地方加标记 dfs(x,y);//继续搜索下一个点 --vis[i][j];//回溯取消标记 } } }
BFS
较DFS高效,找到最快到达目标的一条路径,借助队列实现,状态A的子状态均入队。队列不为空时,弹出队首元素,进行搜索-->队列空;
void judge(node){ if(非法条件为真 || 范围越界) return false; return true; } void bfs(A){ queue<node> q; q.push(A); while(!q.empty()){ temp = q.front(); q.pop(); if(temp 达成目标条件){ 输出信息; } if(judge(temp)){//子状态合法则入队 q.push(temp); ++vis[temp];//每个节点只访问一次 } } }
洛谷 P1443 马的遍历
int n,m,sx,sy,map[410][410],dir[2][4] = {{-2,-1,1,2},{-2,-1,1,2}}; bool vis[410][410]; memset(vis,false,sizeof(vis)); memset(map,0xff,sizeof(map));//初始化为-1 struct point{ int x; int y; }node,top; //马走日字... 坐标 1 2 或 2 1 变换 bool judge(int i,int j){ if(i < 0 || i >= n || j < 0 || j >= m) return false; if(vis[i][j]) return false; return true; } void bfs(int x,int y){ vis[x][y] = 1; map[x][y] = 0;//到初始点需要0步 queue<point> t; node.x = x; node.y = y; t.push(node); while(!t.empty()){ top = t.front(); t.pop(); for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ if(abs(dir[0][i]) != abs(dir[1][j])){//排除不合法的移动 int _x = top.x + dir[0][i]; int _y = top.y + dir[1][j]; if(judge(_x,_y)){//判断这一步是否合法 node.x = _x; node.y = _y; t.push(node); vis[_x][_y] = 1;//标记 第一次到达该点的步数一定最优 map[_x][_y] = map[top.x][top.y] + 1;//路径+1 } } } } } }