搜索(bfs+dfs)

搜索

在咱們瞭解了遞歸以後就能夠拿來作一些事♂情♂,好比走迷宮問題,那麼這個時候咱們就要用到搜索算法。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();//清除已經訪問過的名單
    }
}
題目:

洛谷P1443

代碼:

#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;
    }
}

洛谷P2895

代碼:

#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";
}
相關文章
相關標籤/搜索