在咱們瞭解了遞歸以後就能夠拿來作一些事♂情♂,好比走迷宮問題,那麼這個時候咱們就要用到搜索算法。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"; }