搜索
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1728
BFS:从一个图的某个顶点出发,首先访问与v节点相邻切未被访问过的节点v1,v2,v3,v4..... ,然后依次访问与v1,v2,v3,v4...相邻且未被访问过的节点,
由此可以得到 BFS进行搜索所搜索的节点都是按深度进行扩展的,先找到到V0距离为1的所有节点,然后找到距离V0为2的节点……所以BFS所搜索到的都是最短的路径。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; char map[105][105]; int n, m; struct node { int i, j; int step; //保存转弯数 } q, p; int x2, y2, k; bool v[105][105]; int move[4][2]= {1, 0, -1, 0, 0, 1, 0, -1}; bool pan(int x, int y) //判断坐标是否ok { if(x<0 || x>=n || y<0 || y>=m) return false; if(map[x][y]=='*') return false; return true; } bool BFS(node q) { queue<node> Q; Q.push(q); memset(v, 0, sizeof(v)); v[q.i][q.j]=1; while(!Q.empty()) { q=Q.front(); Q.pop(); if(q.step >= k) continue; for(int i=0; i<4; i++) { p.i=q.i+move[i][0]; p.j=q.j+move[i][1]; p.step=q.step+1; while(1) //从一个方向往下搜索 { if(!pan(p.i, p.j)) break; if(p.i==x2&&p.j==y2) return true; if(!v[p.i][p.j]) //遇到没有标记的进行标记 { v[p.i][p.j]=1; Q.push(p); } p.i += move[i][0]; p.j += move[i][1]; } } } return false; } int main() { int t, i; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); for(i=0; i<n; i++) scanf("%s", map[i]); scanf("%d%d%d%d%d", &k, &q.j, &q.i, &y2, &x2); q.j--, q.i--, x2--,y2--; //地图上是(0,0)开始的 q.step=-1; //第一次选择方向时,没有转弯 if(BFS(q)) puts("yes"); else puts("no"); } return 0; }
DFS:可以看出是尽可能“深”的在图中进行搜索。 如果被访问的节点还有相邻的节点且未被访问,则访问此节点,如果找不到,则返回被访问节点的上一个节点。这一过程一直进行直到所有的节点都被访问为止。 DFS可以搜索出从某一个节点到另外的一个节点的所有路径。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define M 0x7fffffff int x_m[4] = {0, 1, 0, -1}; int y_m[4] = {1, 0, -1, 0}; int x2, y2, k, n, m, flag; char map[105][105]; int v[105][105]; void DFS(int x, int y, int f) { if(x==x2 && y==y2) //当前坐标达到目标点 { if(v[x][y] <= k) flag = 1; return ; } if(v[x][y] > k) return ; //当前坐标时的转弯数 大于 限定值 if(v[x][y]==k && x!=x2 && y!=y2) return ;//这里x,y之间不能用‘或’自己体会 for(int i=0; i<4; i++) { int tx = x+x_m[i]; int ty = y+y_m[i]; if(tx<0 || tx>=m || ty<0 || ty>=n) //越界则想下一个方向进行 continue; if(v[tx][ty] < v[x][y] || map[tx][ty] == '*') //当前状态不能行走时 continue ; if(f!=-1 && f!=i && v[tx][ty] < v[x][y]+1) //当前状态的点转的弯数比上一状态+1还少 continue; v[tx][ty] = v[x][y]; if(f!=-1 && i!=f) v[tx][ty]++; DFS(tx, ty, i); if(flag) return ; } } int main() { int t, i, x1, y1, j; scanf("%d", &t); while(t--) { scanf("%d%d", &m, &n); for(i=0; i<m; i++) scanf("%s", map[i]); scanf("%d%d%d%d%d", &k, &y1, &x1, &y2, &x2); x1--,x2--,y1--,y2--; for(i=0; i<m; i++) //未走的点的弯数标记为无穷大 for(j=0; j<n; j++) v[i][j] = M; v[x1][y1] = 0; flag = 0; DFS(x1,y1,-1); printf("%s\n", flag ? "yes" : "no"); } return 0; }
知识:
头文件 #include<queue>
队列:
queue<类型> Q;
Q.push(a) 数据a接入队尾
Q.pop() 弹出队列第一个元素
Q.front() 返回队首元素
Q.back() 返回队尾元素
Q.empty() 判断队列是否为空 空返true
Q.size() 返回队列元素
优先队列:
操作中没有front,
top返回优先级最大的
Q.top() 其余不变
初始化队列
1.系统默认优先级(大->小)
priority_queue<int> qi;
2. 自定义优先级
结构体
struct node { friend bool operator< (const node &n1, const node &n2) { return n1.priority > n2.priority; //小的先出队 } int priority; int value; }; priority_queue<node> qi;
还有一种运用另一个函数的,感觉先把这两种弄懂再说~~
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1242
大意:一个n*m 的牢房,#代表墙,a代表目标,r代表起点,x代表守卫。每走一步需要1点能量,每打败一个守卫需要1点能量。 从起点到目标点需要最小能量 不能达到则输出
“Poor ANGEL has to stay in the prison all his life.”
思路:这个有个达到守卫需要能量,so BFS+优先队列~~
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; struct nn //节点结构 { int i, j, step; friend bool operator < (const nn &a, const nn &b) //定义优先队列 小的先出队 { return a.step > b.step; } }; //行,列 可以走的坐标点 int i_m[4] = {0, 1, 0, -1}; int j_m[4] = {-1, 0, 1, 0}; int n, m; int v[205][205], step; char map[205][205]; void BFS(int x1, int y1) //需要最短步骤,so用BFS 且 要用优先队列应为遇到敌人时打败需要时间。 { priority_queue<nn> Q; memset(v, 0, sizeof(v)); step = -1; //初始化 nn q, p; q.i = x1; q.j = y1; q.step = 0; Q.push(q); //将起点入队 v[x1][y1] = 1; while(!Q.empty()) { q = Q.top(); //拿出队首元素 Q.pop(); if(map[q.i][q.j] == 'a') //当前点是目标点 { step = q.step; return ; } for(int i=0; i<4; i++) { p.i = q.i+i_m[i]; p.j = q.j+j_m[i]; if(0<=p.i && p.i<n && 0<=p.j && p.j<m && !v[p.i][p.j] && map[p.i][p.j]!='#') //当前点符合要求 { if(map[p.i][p.j]=='x') p.step = q.step+2; else p.step = q.step+1; v[p.i][p.j] = 1; //将当前点进行标记 Q.push(p); //当前点入队列 } } } } int main() { int i, j, x1, y1; while(scanf("%d%d", &n, &m) != EOF) { for(i=0; i<n; i++) scanf("%s", map[i]); for(i=0; i<n; i++) for(j=0; j<m; j++) if(map[i][j] == 'r') { x1 = i; y1 = j; break; } BFS(x1,y1); if(step == -1) printf("Poor ANGEL has to stay in the prison all his life.\n"); else printf("%d\n", step); } return 0; }
大意:一个8*8的棋盘,遵循象棋中‘马’的走法。给你起点和终点,问最少需要多少步可以到达~
思路: 需要求最少 即BFS。

浙公网安备 33010602011771号