算法题——深度优先搜索
DFS的模板
判断能否从一个点走到终点
bool dfs(v) { if (v为终点) { return true; } if (v是走过的点) { return false; } //v是未走过的点 操作1:将v标记为旧点(已经走过的点) 操作2:对和v相邻的每个节点u,执行如下操作 { if (dfs(u) == true) { //从v到u,最终可以到终点 return true; } } //从v不能走到终点 return false; }
判断从一个点能否走到终点,如果能的话,记录路径
Node path[MAX_LEN]; //记录路径 int depth; //记录深度(走的步数) bool dfs(v) { if (v为终点) { path[depth] = v; return true; } if (v是走过的点) { return false; } //v是未走过的点 操作1:将v标记为旧点(已经走过的点) path[depth] = v; ++depth; 操作2:对和v相邻的每个节点u,执行如下操作 { if (dfs(u) == true) { //从v到u,最终可以到终点 return true; } } //从v不能走到终点,回退一步,深度减1 --depth; return false; } int main(){ depth = 0; if (dfs(起点)) { //如果能走到终点,就打印路径 for (int i = 0; i < depth; i++) { cout << path << endl; } } }
例题1:城堡问题
http://bailian.openjudge.cn/practice/2815
#include<iostream> #include<algorithm> using namespace std; int R, C; //行列数 int rooms[60][60]; //输入每个房间的情况:1、西墙;2、北墙;4、东墙;8、南墙 int color[60][60]; //房间是否已经走过 int maxRoomArea = 0; //最大的房间面积 int roomNum =0; //房间数量 int roomArea; //用来记录每个房间的面积j void dfs(int i, int j) // 从room[i][j]开始进行dfs操作 { if (color[i][j]){ //已经走过的点 return; } //否则是没有走过的点 ++roomArea; //房间面积加1 color[i][j] = roomNum; //给这个没有走过的房间做标记(表示已经走过了) if ((rooms[i][j] & 1) == 0) { //西边没有墙 dfs(i, j-1); } if ((rooms[i][j] & 2) == 0) { //北边没有墙 dfs(i-1, j); } if ((rooms[i][j] & 4) == 0) { //东边没有墙 dfs(i, j+1); } if ((rooms[i][j] & 8) == 0) { dfs(i+1, j); } } int main() { cin >> R >> C; for (int i = 0; i < R; i++) { for (int j = 0; j < C; j++) { cin >> rooms[i][j]; color[i][j] = 0; } } for (int i = 0; i < R; i++) { for (int j = 0; j < C; j++) { //循环遍历图中的每个点,如果color[i][j]为0,表示这里可以作为一个新房间的起点 //如果color[i][j]为1,表示这个房间已经走过了,那么就不再进行搜索了 if (!color[i][j]) { ++roomNum; //房间的数量加1 roomArea = 0; //当前房间的最大面积 dfs(i, j); maxRoomArea = max(roomArea, maxRoomArea); } } } cout << roomNum << endl; cout<< maxRoomArea << endl; }
例题2:踩方块
http://bailian.openjudge.cn/practice/4103/
#include<iostream> using namespace std; int visited[30][50]; int ways(int i, int j, int n) { if (n == 0){ return 1; } visited[i][j] = 1; // 将此步标记为1 int num = 0; if (! visited[i][j-1]) { //向西走 num += ways(i, j-1, n-1); } if (! visited[i][j+1]) { num += ways(i, j+1, n-1); } if(! visited[i+1][j]) { num += ways(i+1, j, n-1); } visited[i][j] = 0; //离开的时候,将此步标记为未走过 return num; } int main(){ int n; while (cin >> n) { cout << ways(0, 25, n) << endl; } return 0; }
例题3:Roads
http://poj.org/problem?id=1724
例题4:泉水淹没的面积
Description
有一个泉眼,由于当地的地势不均匀,有高有低,这个泉眼不断的向外溶出水来,这意味着这里在不久的将来将会一个小湖。水往低处流,凡是比泉眼地势低或者等于的地方都会被水淹没,地势高的地方水不会越过。而且又因为泉水比较弱,当所有地势低的 地方被淹没后,水位将不会上涨,一直定在跟泉眼一样的水位上。 所有的地图都是一个矩形,并按照坐标系分成了一个个小方格,Leyni知道每个方格的具体高度。我们假定当水留到地图边界时,不会留出地图外,现在他想通过这些数据分析出,将来这里将会出现一个多大面积的湖
Input
有若干组数据,每组数据的第一行有四个整数n,m,p1,p2(0<n,m,p1,p2<=1000),n和m表示当前地图的长和宽,(p1,p2)表示当前地图的泉眼位置。在n*m的矩阵里每个数字表示这每一个对应坐标的高度。
Output
输出对应地图中会有多少个格子被水充满。
Sample Input
3 5 2 3
3 4 1 5 1
2 3 3 4 7
4 1 4 1 1
Sample Output
6
#include<iostream> #include<stack> #include<cstring> using namespace std; int arr[1000][1000]; bool visit[1000][1000]; int n, m, x, y; int h; //泉眼的高度 int sum = 0; int dfs(int i, int j) { if (visit[i][j]){ //已经走过 return 0; } visit[i][j] = true; sum += 1; if (i-1 >= 1 && arr[i-1][j] <= h) { //上 dfs(i-1,j); } if (i+1 <=n && arr[i+1][j] <= h) { dfs(i+1, j); } if (j-1 >= 1 && arr[i][j-1] <= h) { dfs(i, j-1); } if (j+1 <=n && arr[i][j+1] <= h) { dfs(i, j+1); } return sum; } int main() { while(cin >> n >> m >> x >> y) { memset(visit, false, sizeof(visit)); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> arr[i][j]; } } h = arr[x][y]; dfs(x, y); cout << sum << endl; } return 0; }
如需转载,请注明文章出处,谢谢!!!