算法总结—深度优先搜索DFS
2016-06-13 13:39
513 查看
深度优先搜索(DFS)
往往利用递归函数实现(隐式地使用栈)。
深度优先从最开始的状态出发,遍历所有可以到达的状态。由此可以对所有的状态进行操作,或列举出所有的状态。
1.poj2386LakeCouting
题意:八连通被认为连接在一起,求总共有多少个水洼?
SampleInput:
SampleOutput
2.poj1979RedandBlack
题意:@表示起点,可以上下左右四方向走,"."为黑色,可以走,“#”为红色,不可以走,问可以到达多少个黑色位置?
SampleInput
SampleOutput
3.aoj0118PropertyDistribution
题意:苹果是@,梨是#,蜜柑是*。四连通且相同品种在一个区域。计算每组数据区域的个数。
SampleInput:
OutputfortheSampleInput
SampleInput
OutputfortheSampleInput
5.poj3009Curling2.0
题意:
可以沿上下左右走到障碍物,碰到障碍物后停下,障碍物消失,然后可以继续出发,出界算失败,超过十步算失败,问能否从S到G,
不能输出-1,能输出最少步数。(0路径,1障碍物,2起点,3终点)
SampleInput
SampleOutput
思路:这种走到底的题目也可以用DFS,设计成无返回值,到达3后比较当前值与已有最小值的大小。注意走到底的写法(while)
代码:
6.poj1321棋盘问题
题意:n*n矩阵形状的棋盘(“#”为可摆放棋盘区域,“.”为不可摆放空白区域),要摆放k个棋子,同行同列不能有两个,共多少种方案?
SampleInput
SampleOutput
往往利用递归函数实现(隐式地使用栈)。
深度优先从最开始的状态出发,遍历所有可以到达的状态。由此可以对所有的状态进行操作,或列举出所有的状态。
1.poj2386LakeCouting
题意:八连通被认为连接在一起,求总共有多少个水洼?
SampleInput:
1012 W........WW. .WWW.....WWW ....WW...WW. .........WW. .........W.. ..W......W.. .W.W.....WW. W.W.W.....W. .W.W......W. ..W.......W.
SampleOutput
3 思路:从任意W开始,一次DFS把连通的.全部变为W,遍历图直到没有.为止,进行DFS次数即为水洼的个数。 代码:
#include<iostream> usingnamespacestd; intN,M; charpond[100][100];//globalvariable voiddfs(inti,intj){//注意参数设计,要不要返回值 pond[i][j]='.'; for(intdx=-1;dx<=1;++dx){//八连通遍历方式,四连通往往事先开好数组,见后续题目 for(intdy=-1;dy<=1;++dy){ intx=i+dx,y=j+dy; if(x>=0&&x<N&&y>=0&&y<M&&pond[x][y]=='W'){ dfs(x,y); } } } return; } intmain(){ cin>>N>>M; for(inti=0;i<N;++i){ for(intj=0;j<M;++j){ cin>>pond[i][j]; } } intcount=0; for(inti=0;i<N;++i){ for(intj=0;j<M;++j){ if(pond[i][j]=='W'){ dfs(i,j); count++; } } } cout<<count<<endl; }
2.poj1979RedandBlack
题意:@表示起点,可以上下左右四方向走,"."为黑色,可以走,“#”为红色,不可以走,问可以到达多少个黑色位置?
SampleInput
69 ....#. .....# ...... ...... ...... ...... ...... #@...# .#..#. 119 .#......... .#.#######. .#.#.....#. .#.#.###.#. .#.#..@#.#. .#.#####.#. .#.......#. .#########. ........... 116 ..#..#..#.. ..#..#..#.. ..#..#..### ..#..#..#@. ..#..#..#.. ..#..#..#.. 77 ..#.#.. ..#.#.. ###.### ...@... ###.### ..#.#.. ..#.#.. 00
SampleOutput
45 59 6 13
思路:从起点处DFS遍历即可,当前点为“.”则将其改为“#”,result++,并以该点出发继续遍历。 代码:
#include<iostream> usingnamespacestd; charrect[20][20]; intresult=0;//全局的result intdx[4]={-1,0,0,1};//四连通处理方法 intdy[4]={0,1,-1,0}; intW=1,H=1; voiddfs(intsx,intsy){ rect[sx][sy]='#'; result++; for(inti=0;i<4;++i){ intx=sx+dx[i],y=sy+dy[i]; if(x>=0&&x<H&&y>=0&&y<W&&rect[x][y]=='.'){ dfs(x,y); } } return; } intmain(){ while(W!=0&&H!=0){ cin>>W>>H; if(W==0&&H==0){ return0; } intsx,sy; for(inti=0;i<H;++i){ for(intj=0;j<W;++j){ cin>>rect[i][j]; if(rect[i][j]=='@'){ sx=i; sy=j; } } } dfs(sx,sy); cout<<result<<endl; result=0; } return0; }
3.aoj0118PropertyDistribution
题意:苹果是@,梨是#,蜜柑是*。四连通且相同品种在一个区域。计算每组数据区域的个数。
SampleInput:
1010 ####*****@ @#@@@@#*#* @##***@@@* #****#*@** ##@*#@@*## *@@@@*@@@# ***#@*@##* *@@@*@@##@ *@*#*@##** @****#@@#@ 00
OutputfortheSampleInput
33
思路:类似第一题的池塘数个数的思路,DFS遍历,将遍历完毕的节点改为不同于上述三种标志的第四种标志,如“X”, 并且在DFS函数中加入标志参数用于判断同类水果区域,一次DFS,result++,当所有标志为X时,遍历结束。 代码:
#include<iostream> usingnamespacestd; chargarden[100][100]; intH=1,W=1; intresult=0; intdx[4]={-1,0,0,1}; intdy[4]={0,1,-1,0}; voiddfs(intsx,intsy,charc){//加入char判断是否同一类 garden[sx][sy]='x'; for(inti=0;i<4;++i){ intx=sx+dx[i],y=sy+dy[i]; if(x>=0&&x<H&&y>=0&&y<W&&garden[x][y]==c){ dfs(x,y,c); } } return; } intmain(){ while(H!=0&&W!=0){ cin>>H>>W; if(H==0&&W==0){ return0; } for(inti=0;i<H;++i){ for(intj=0;j<W;++j){ cin>>garden[i][j]; } } for(inti=0;i<H;++i){ for(intj=0;j<W;++j){ if(garden[i][j]!='x'){ dfs(i,j,garden[i][j]); result++; } } } cout<<result<<endl; result=0; } }
4.aoj0033Ball 题意:A管进球,B,C管出球,给定如球顺序,判断能否移动挡板,使得B,C出球顺序均为从下往上标号递增。
SampleInput
2 31425678910 10987654321
OutputfortheSampleInput
YES NO
思路:DFS遍历,一个参数记录当前到第几个球,另外两个记录当前B,C顶端球得数值,以便于比较。 代码:
#include<iostream> usingnamespacestd; intA[10]; booldfs(intstart,inttopB,inttopC){//有返回值的DFS if(start==9){//最后一个球啦 if(A[start]>topB||A[start]>topC){ returntrue; } else{ returnfalse; } } boolb1=false,b2=false; if(A[start]>topB){//B可以放,放进去试 b1=dfs(start+1,A[start],topC); } if(A[start]>topC){//C可以放,放进去试 b2=dfs(start+1,topB,A[start]); } return(b1||b2);//B,C都不可以放的时候,返回false,否则true } intmain(){ intN; cin>>N; for(inti=0;i<N;++i){ for(intj=0;j<10;++j){ cin>>A[j]; } boolresult=dfs(0,0,0); if(result==true){ cout<<"YES"<<endl; } else{ cout<<"NO"<<endl; } } return0; }
5.poj3009Curling2.0
题意:
可以沿上下左右走到障碍物,碰到障碍物后停下,障碍物消失,然后可以继续出发,出界算失败,超过十步算失败,问能否从S到G,
不能输出-1,能输出最少步数。(0路径,1障碍物,2起点,3终点)
SampleInput
21 32 66 100210 110000 000003 000000 100001 011111 61 112113 61 102113 121 201111111113 131 2011111111113 00
SampleOutput
1 4 -1 4 10 -1
思路:这种走到底的题目也可以用DFS,设计成无返回值,到达3后比较当前值与已有最小值的大小。注意走到底的写法(while)
代码:
#include<iostream> #include<cstring> #include<limits.h> usingnamespacestd; intboard[21][21]; intW=1,H=1; intdx[4]={-1,0,0,1}; intdy[4]={0,1,-1,0}; intsx,sy,minStep=INT_MAX; voiddfs(intsx,intsy,intstep){//设计成无返回值,当board[i][j]==3时比较当前step+1与最小的step并更新 if(step>=10){//剪枝 return; } for(inti=0;i<4;++i){ intx=sx+dx[i],y=sy+dy[i]; if(x>=0&&x<H&&y>=0&&y<W&&board[x][y]!=1){ while(x>=0&&x<H&&y>=0&&y<W&&board[x][y]!=1){//走到底的判断 if(board[x][y]==3){ if(step+1<minStep){ minStep=step+1; break; } } x+=dx[i]; y+=dy[i]; if(board[x][y]==1){ board[x][y]=0; dfs(x-dx[i],y-dy[i],step+1); board[x][y]=1;//恢复状态 } } } } return; } intmain(){ while(W!=0&&H!=0){ cin>>W>>H; if(W==0&&H==0){ return0; } memset(board,0,sizeof(board)); for(inti=0;i<H;++i){ for(intj=0;j<W;++j){ cin>>board[i][j]; if(board[i][j]==2){ sx=i; sy=j; } } } dfs(sx,sy,0); if(minStep==INT_MAX){ cout<<"-1"<<endl; } else{ cout<<minStep<<endl; } minStep=INT_MAX; } return0; }
6.poj1321棋盘问题
题意:n*n矩阵形状的棋盘(“#”为可摆放棋盘区域,“.”为不可摆放空白区域),要摆放k个棋子,同行同列不能有两个,共多少种方案?
SampleInput
21 #. .# 44 ...# ..#. .#.. #... -1-1
SampleOutput
2 1 思路:DFS的思路,一行一行的确定摆放位置,开一个数组place[8]记录哪一列已经有摆放。 注意k如果小于N时,可以有某一行不摆放元素,所以代码24行DFS(row+1,num)必须添加。 代码:
#include<iostream> #include<cstring> usingnamespacestd; intN=1,K=1; charchess[8][8]; intresult=0; intplaced[8]={0};//记录该列是否有摆放 voiddfs(introw,intnum){ if(num==K){//摆放成功,方案数++ result++; return; } if(row==N){ return; } for(inti=0;i<N;++i){ if(chess[row][i]=='#'&&placed[i]==0){ placed[i]=1; dfs(row+1,num+1); placed[i]=0; } } dfs(row+1,num);//!容易忽略 } intmain(){ while(N!=-1&&K!=-1){ cin>>N>>K; if(N==-1&&K==-1){ return0; } memset(chess,0,sizeof(chess)); memset(placed,0,sizeof(placed)); for(inti=0;i<N;++i){ for(intj=0;j<N;++j){ cin>>chess[i][j]; } } dfs(0,0); cout<<result<<endl; result=0; } }
相关文章推荐
- 桶排序
- C++中的单例模式
- Android LayoutInflater详解
- 堆排序
- 月薪3万的程序员告诉你:这样工作才能拿高薪
- Android有效地减少方法数
- 基数排序
- 命名空间中的“MvcBuildViews”。 无效
- 四大组件之Service(二)-Service在各种情况下的生命周期
- STL之*min_element , *max_element ,*nth_element()[取容器中最大元素 最小元素 第n元素]
- 怎样在Eclipse中快速查看各种源代码?
- 【Spring4揭秘】修改Bean---BeanPostProcessor
- 鼠标双击
- myeclipse快捷键
- CountDownTimer 解决 Cancel无效的问题
- 转:java中时间戳各种实现方式获取效率
- 归并排序
- 深入Java集合:ArrayList实现原理
- 什么是编解码器codec
- 第十。十一周项目3 - 警察和厨师——1