DFS(11)
2020-02-02 19:45
148 查看
DFS(主要还是靠大家慢慢理解)
说实话,写这种博客我也挺难的。。。
因为他的内容太不好理解了
也没得什么好说的,直接做题理解吧。
先来一个特别有意思的递归题。
传送门: 放苹果 POJ - 1664
#include <stdio.h> using namespace std; typedef long long ll; int n,m,ans; int DFS(int m,int n) { if(n==0||n==1) return 1; if(n>m) return DFS(m,m); else return DFS(m-n,n)+DFS(m,n-1); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d %d",&m,&n); printf("%d\n",DFS(m,n)); } return 0; }
传送门:Red and Black HDU - 1312
是不是感觉特熟悉,没错,上次写这个题用的是BFS,这次用的是DFS
#include<bits/stdc++.h> using namespace std; typedef long long ll; int xx,yy,x11,y11,ans; char c[25][25]; int vis[25][25]; int dd[4][2]={1,0,-1,0,0,1,0,-1}; void DFS(int x,int y) { vis[x][y]=1; if(x<0||y<0||x>=xx||y>=yy) return ; for(int i=0;i<4;i++) { int dx=x+dd[i][0]; int dy=y+dd[i][1]; if(dx>=0&&dy>=0&&dx<xx&&dy<yy&&vis[dx][dy]==0&&c[dx][dy]!='#') { ans++; DFS(dx,dy); } } } int main() { while(~scanf("%d %d",&yy,&xx)&&yy&&xx) { ans=1; memset(vis,0,sizeof vis); for(int i=0;i<xx;i++) { for(int j=0;j<yy;j++) { cin>>c[i][j]; if(c[i][j]=='@') { x11=i; y11=j; } } } DFS(x11,y11); cout<<ans<<endl; } return 0; }
传送门:Oil Deposits HDU - 1241
还是用了个老方法,把走过的变成‘*’,还可以再开一个数组进行标记。
#include<bits/stdc++.h> using namespace std; typedef long long ll; int xx,yy,x11,y11,ans; char c[110][110]; int vis[110][110]; int dd[8][2]={1,0,-1,0,0,1,0,-1,1,1,-1,-1,1,-1,-1,1}; void DFS(int x,int y) { c[x][y]='*'; for(int i=0;i<8;i++) { int dx=x+dd[i][0]; int dy=y+dd[i][1]; if(dx>=0&&dy>=0&&dx<xx&&dy<yy&&c[dx][dy]!='*') //不走出边界 { DFS(dx,dy); } } } int main() { while(~scanf("%d %d",&xx,&yy)&&yy&&xx) { ans=0; for(int i=0;i<xx;i++) cin>>c[i]; for(int i=0;i<xx;i++) { for(int j=0;j<yy;j++) { if(c[i][j]=='@') { DFS(i,j); ans++; } } } cout<<ans<<endl; } return 0; }
传送门:Fox And Two Dots CodeForces - 510B (涉及到新方法)
//#include <bits/stdc++.h> #include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long int ll; int xx,yy,flag; int vis[55][55]; char map[55][55]; int dx[4]={0,1,0,-1}; int dy[4]={1,0,-1,0}; void dfs(int a,int b,int aa,int bb) { int k; char c=map[a][b]; for(int k=0;k<4;k++) { int x=a+dx[k]; int y=b+dy[k]; if(map[x][y]==c&&x>=0&&y>=0&&x<xx&&y<yy) { if(x==aa&&y==bb) //因为是4个方向都要遍历,防止遍历时又退回上一步 continue; if(vis[x][y]) { flag=1; return ; } vis[x][y]=1; dfs(x,y,a,b); } } } int main() { while(~scanf("%d%d",&xx,&yy)) { flag=0; memset(vis,0,sizeof vis); for(int i=0;i<xx;i++) cin>>map[i]; for(int i=0;i<xx;i++) { for(int j=0;j<yy;j++) { if(!vis[i][j]) dfs(i,j,-1,-1); if(flag) break; } } if (flag) printf ("Yes\n"); else printf ("No\n"); } return 0; }
N皇后问题 HDU - 2553 (超级经典,一定要好好感受里面的回溯思想)
当初不会这个题,然后就让N=4,然后就一直手跑2个多小时,最后终于跑出来了。。。
#include <bits/stdc++.h> using namespace std; typedef long long int ll; int N,cot; //分别代表棋盘尺寸(皇后数量)和皇后可能成功摆放的结果总数 int size[11];//数组的下标表示行,对应的值表示列 int ans[11]; // 用于打表存放结果 void dfs(int n) { int flag; if(n==N+1) //当 最后一个皇后成功放置时返回. { cot++; //成功的次数加一 return ; } for(int i=1;i<=N;i++) { size[n]=i; //代表将第一个皇后放置在第1行第i列(或者说第n个皇后) flag=1; //放完之后就行标记 for(int j=1;j<n;j++) //这个for循环用来检测 这个皇后的位置和之前的n个皇后的位置是否冲突 { if(size[j]==i||((abs(n-j))==abs(size[j]-i))) //判断条件 { flag=0; break; } } if(flag) dfs(n+1); // 如果放置在第i列不冲突 则开始放下一个皇后 如果冲突 放在下一列继续判断 } } int main() { for( N=1;N<=11;N++)//因为本题时间限制,所以需要先打表 { cot=0; //临时存放结果 dfs(1); ans[N]=cot; // 将结果依次放入表中 } while(cin >>N) { if(!N) break; cout <<ans[N]<<endl; } return 0; }
传送门:Tempter of the Bone HDU - 1010 (奇偶剪枝)
大体的题意就不说了,就是DFS+奇偶剪枝。在这个题里有一个很牛的方法:奇偶剪枝,不会这个基本做不出来这个题,这里就不给大家简绍了,大家直接百度,里面的大佬写的太好了。
#include <bits/stdc++.h> using namespace std; typedef long long int ll; int n,m,T,flag,ti; //ti是步数 char c[10][10]; int vis[10][10]; int x_1,y_1,x2,y2; int dd[4][2]={-1,0,1,0,0,1,0,-1}; void dfs(int x,int y) { if(x<0||y<0||x>=m||y>=n||ti>T) return ; //超出范围或者步数超了直接就剪掉 if(flag) return ; //找到答案就剪掉 if(x==x2&&y==y2&&ti==T) //出口的判断 { flag=1; return ; } int dis=abs(T-ti-(abs(x2-x)+abs(y2-y))); //传说中的奇偶剪枝 if(dis<0||dis%2) //我也是第一次用,感觉好厉害 return ; vis[x][y]=1; for(int i=0;i<4;i++) { int dx=x+dd[i][0]; int dy=y+dd[i][1]; if(dx>=0&&dy>=0&&dx<m&&dy<n&&!vis[dx][dy]&&c[dx][dy]!='X') { ti++; dfs(dx,dy); vis[dx][dy]=0; //回溯思想 ti--; } } } int main() { ios::sync_with_stdio(false); while(cin>>n>>m>>T) { ti=0; flag=0; memset(vis,0,sizeof vis); if(n==0&&m==0&&T==0) break; for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { cin>>c[i][j]; if(c[i][j]=='S') { x_1=i; y_1=j; } if(c[i][j]=='D') { x2=i; y2=j; } } } dfs(x_1,y_1); if(flag) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }
传送门:棋盘问题 POJ - 1321
上面那么难的问题都解决了,这个一定会。
//#include <bits/stdc++.h> #include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long int ll; int n,k,m,sum; char c[10][10]; int vis[10][10]; int a[10]; void dfs(int cur) { if(k==m) { sum++; return ; } if(cur>=n) return ; for(int j=0;j<n;j++) { if(a[j]==0&&c[cur][j]=='#') { a[j]=1; m++; dfs(cur+1); a[j]=0; m--; } } dfs(cur+1); } int main() { while(scanf("%d%d",&n,&k)&&n!=-1&&k!=-1) { sum=0; memset(a,0,sizeof a); for(int i=0;i<n;i++) cin>>c[i]; dfs(0); cout<<sum<<endl; } return 0; }
传送门: Sudoku POJ - 2676
我的天哪,难死了,写了好长时间一直不对。。。
给一个CV代码,大家慢慢理解吧,。。。。
这道题的处理方式很巧妙。dfs中的参数只设置一个n(n就是代表着这是第几个数)就够了,就是当前的位置,在dfs中每次加一,如果当前位置不为0,就直接查找下一个位置。否则就从1~9中选一个数放进去,看同一行同一列以及同一小方格的同一行同一列有没有与之相同的,如果没有,就将当前位置的数更新成这个没有重复出现过的数。知道查找到n>=81的时候,即每个位置都查找完了,结束查找输出即可。注意在查找的过程中需要用到回溯,因为如果这一条路行不通而返回上一条路的时候,此时当前位置还应该是0.
n/9代表的就是当前位置的行,n%9代表的就是当前位置的列。
n/9/33表示的就是当前位置在小方格里的行,n%9/33代表的就是当前位置在小方格里的列。
#include<iostream> #include<cstdio> using namespace std; int a[10][10],flag; // n/9代表的就是当前位置的行,n%9代表的就是当前位置的列。 // n/9/3*3表示的就是当前位置在小方格里的行. // n%9/3*3代表的就是当前位置在小方格里的列。 bool check(int n,int now) { for(int i=0;i<9;i++) { int j=n%9; if(a[i][j]==now) return 0; } for(int j=0;j<9;j++) { int i=n/9; if(a[i][j]==now) return 0; } int di=n/9/3*3; int dj=n%9/3*3; for(int i =di;i<di+3;i++) { for(int j=dj;j<dj+3;j++) { if(a[i][j]==now) return 0; } } return 1; } int dfs(int n) { if(n>=81) { flag=1; return 0; } if(a[n/9][n%9]!=0) dfs(n+1); else { for(int i=1;i<=9;i++) { if(check(n,i)==1) { a[n/9][n%9]=i; dfs(n+1); if(flag==1) return 0; a[n/9][n%9]=0;//回溯 } } } // cout<<"?"<<endl; } int main() { int t; cin>>t; while(t--) { flag=0; for(int i=0;i<9;i++) for(int j=0;j<9;j++) scanf("%1d",&a[i][j]); //一个贼有意思的输入 dfs(0); for(int i=0;i<9;i++) { for(int j=0;j<9;j++) printf("%d",a[i][j]); puts(""); } } return 0; }
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- 算法总结(11)--伪递归,dfs,动态规划题,需要转换下思路
- leetcode-11-dfs
- DFS算法——ALDS1_11_B(日本AOJ)
- 数据结构(11) -- 邻接表存储图的DFS和BFS
- 11 Inspiring Mobile App Websites
- 对邻接链表的深度优先(DFS)遍历
- HDU 5438 Ponds(dfs)——2015 ACM/ICPC Asia Regional Changchun Online
- CodeForces 384E Propagating tree (dfs序)
- 图结构练习——BFSDFS——判断可达性
- dfs练习
- 11.字典:当索引不好用时
- 程序是怎样跑起来的(11)----硬件控制方法
- iPhone 11预售现“真香” 降价能否救苹果?
- Fedora 11 Beta 跳票了
- 错误602:未能在sysindexes中找到数据库ID11中对象ID1的索引ID1对应的行
- hdu 1241 Oil Deposits_dfs or bfs
- 杭电2181 哈密顿绕行世界问题(DFS)
- 11-EMM Procedure 1. Initial Attach Part2
- Poj 1856 Sea Battle【Dfs+思维】
- ACM暑期集训——专题一[DFS回溯法]