在咱们了解了递归以后就能够拿来作一些事♂情♂,好比走迷宫问题,那么这个时候咱们就要用到搜索算法。node
咱们平时走迷宫容易见到的策略是:走一条路走到底并放线作标记,若是碰到墙壁就把线收回到上一个路口。ios
这样就引出了dfs的思想:穷尽每一步出现的全部方式,直到找到解为止。c++
模板:算法
void dfs(int n){ if(n>=k){//知足条件或者到底了 .....(所要求的步骤) return ; } for(int i=1;i<=m;i++){ if(a[i]!=0(若是没有被标记到)&&(其余条件)){ a[i]=1;//作标记(放线) dfs(n+1)//能够是更多的数据,好比总和的继承,或者是层数加进去等。 a[i]=0;//回归上一个状态 } } }
题目:洛谷P1219数据结构
#include<iostream> using namespace std; int z[300],d1[300],d2[300],b[300]; int n,ans=0; int k=0; void dfs(int x) { if(x>n) { ans++; if(k<3) { for(int i=1;i<=n;i++) cout<<b[i]<<" "; cout<<endl; } k++; return; } else for(int i=1;i<=n;i++) { if((!z[i])&&(!d1[i+x])&&(!d2[x-i+n])) { b[x]=i; z[i]=1; d1[i+x]=1; d2[x-i+n]=1; dfs(x+1); z[i]=0; d1[i+x]=0; d2[x-i+n]=0; } } } int main() { cin>>n; dfs(1); cout<<ans; return 0; }
可是问题来了,若是是问去迷宫的最短路,还要在走一次,那么咱们就又会花时间去找这条路走了多少步(或者有多少状况)那么这个时候就能够考虑记忆化(记忆化搜索),也就是把每一次走过的点记下来,而后下次再遇到的时候直接返还以前找过的数值。spa
模板:.net
int dfs(int n){ if(step[n]!=inf){//知足条件或者到底了 return step[n];//返回已经储存的条件 } for(int i=1;i<=m;i++){ if(其余条件){ temp=dfs(n+1)+1;//记录到这个位置会有几步(记忆) step[n]=min(temp,step[n]);//记录最短路径。 } } return step[n];//在最后一个地方须要返回一次,是对第一次作记忆的铺垫 }
洛谷:P1464:code
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll rpt[25][25][25]; ll w(ll a,ll b,ll c) { if(a<=0||b<=0||c<=0) return 1; else if(rpt[a][b][c]!=0) return rpt[a][b][c];//若是有这个结果了,那么直接就返回数值。 else if(a>20||b>20||c>20) rpt[a][b][c]=w(20,20,20); else if(a<b&&b<c) rpt[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c); else rpt[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1); return rpt[a][b][c]; } int main() { ll a,b,c; while(cin>>a>>b>>c){ memset(rpt,0,sizeof(rpt)); if(a==-1&&b==-1&&c==-1) break; printf("w(%lld, %lld, %lld) = ",a,b,c); if(a>20) a=21; if(b>20) b=21; if(c>20) c=21; cout<<w(a,b,c)<<endl; } return 0; }
poj:1088:继承
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #define ll long long using namespace std; int x[10]={0,0,1,-1,0}; int y[10]={0,1,0,0,-1}; int map[1001][1001]; int step[1001][1001]; int sum,ans=-1; int m,n; int dfs(int xx,int yy){ if(step[xx][yy]!=0){ return step[xx][yy]; } for(int i=1;i<=4;i++){ if(map[xx+x[i]][yy+y[i]]<map[xx][yy]&&xx+x[i]>0&&yy+y[i]>0&&xx+x[i]<=n&&yy+y[i]<=m){ int temp=dfs(xx+x[i],yy+y[i])+1; step[xx][yy]=max(temp,step[xx][yy]); } } return step[xx][yy]; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ cin>>map[i][j]; } for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++){ step[i][j]=dfs(i,j); ans=max(step[i][j],ans); } // for(int i=1;i<=m;i++){ // for(int j=1;j<=m;j++){ // cout<<step[i][j]<<"\t"; // } // cout<<'\n'; // } cout<<ans+1<<'\n'; }
这里就好像每次你走到岔路口都会分一次身,知道你找到出口的时候就回收分身。递归
咱们要怎么样实现分身呢?这里咱们会用到一种数据结构:队列。
队列有先进先出的性质,就好像一份访问名单:
队列长度 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
方位 | 路口1(上) | 路口1(下) | 路口3(左) | 路口4(右) | 路口2(路口1走上)(上) | 路口3(路口1走下)(下) | 路口4(路口1箱左) |
.......一直到最后找到出口
由上表会发现,也就是把每一个路口能够的状况都放入队列。
经过q.push()
加入新的要访问的名单,当咱们调查完这个路口时q.pop()
来删除访问名单(队列)里的元素。
代码:
void bfs( ){ queue<结构体>q; q.push(mp[start][start]); while(!q.empty()){ now.x=q.x; now.y=q.y; if(step[endx][endy]!=0){ ans=step[endx][endy];//到终点了,结束 return; } for(int i=1;i<=x;i++){ next.x=now.x+q.x; next.y=now.y+q.y; if(next.x<=边界&&next.y<=边界&&a[next.x][next.y]==0&&mp[next.x][next.y]!=)//a用来判断有没有走过 q.push(next); step[next.x][next.y]=step[now.x][now.y]+1;//刷新步数 } q.pop();//清除已经访问过的名单 } }
代码:
#include<iostream> #include<queue> #include<cstdio> using namespace std; queue<int>x; queue<int>y; int kuan,chang,sx,sy,nx,ny; int fg[401][401]; int fx[9]={2,-2,2,-2,1,-1,1,-1}; int fy[9]={1,1,-1,-1,2,2,-2,-2}; int main() { int step=0; cin>>chang>>kuan>>sx>>sy; nx=sx;ny=sy; for(int i=1;i<=chang;i++) { for(int j=1;j<=kuan;j++) fg[i][j]=-1; } x.push(sx);y.push(sy); fg[sx][sy]=step; step++; while(!x.empty()&&!y.empty()) { for(int i=0;i<=7;i++) { nx=x.front() + fx[i];ny=y.front() + fy[i];//表示从开头开始查找,从某个位置开始 if(fg[nx][ny]==-1&&nx<=chang&&ny<=kuan&&nx>=1&&ny>=1) { x.push(nx);y.push(ny);//下一个位置 fg[nx][ny]=step;//步伐 } } x.pop();y.pop();//判断完了,弹出数据 step=fg[x.front()][y.front()]+1;//这个到地方而后走下一步 } for(int i=1;i<=chang;++i) { for(int j=1;j<=kuan;++j) printf("%-5d", fg[i][j]); cout<<endl; } }
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<vector> using namespace std; #define ll long long int n,z,q,step=0,ans=0,zz,qq; ll x[10]={0,1,-1,0,0}; ll y[10]={0,0,0,1,-1}; int s[1001][1001]; int a[1001][1001]; int b[1001][1001]; int time[1001][1001]; struct node{ int x,y; }; node now,zd; queue <node> h; int main(){ int n,sj=1; cin>>n; for(int i=1;i<=305;i++){ for(int j=1;i<=305;i++) a[i][j]=-1; } for(int i=1;i<=n;i++){ int xx,yy,t; cin>>xx>>yy>>t; for (int j=0;j<5;j++){ if (xx+x[j]>=0&&yy+y[j]>=0&&(a[xx+x[j]][yy+y[j]]==-1||a[xx+x[j]][yy+y[j]]>t)) a[xx+x[j]][yy+y[j]]=t; } } b[1][1]=0; time[1][1]=1; now.x=0,now.y=0; h.push(now); h.pop(); while(!h.empty()) { now=h.front(); sj=time[now.x][now.y]+1; if(a[now.x][now.y]==-1){ cout<<sj<<'\n'; return 0; } h.pop(); for(int i=1;i<=4;i++){ zd.x=now.x+x[i],zd.y=now.y+y[i]; if(zd.x>0&&zd.x<=300&&zd.x>0&&zd.y<=300&&b[zd.x][zd.y]==0&&sj<a[zd.x][zd.y]){ h.push(zd); time[zd.x][zd.y]=sj; b[zd.x][zd.y]=1; } } } cout<<"-1\n"; }