1. 程式人生 > 實用技巧 >DFS【搜尋1】

DFS【搜尋1】

DFS模板

void dfs(int depth)//depth表示當前的層數(或深度)
{
    if(depth>n)//到達葉子節點,該路已走到盡頭
        return;
    for(int i=1;i<=n;i++)//n表示最大的值,即最大深度為n
    {
        if(b[i]==0)//b陣列表示探索的狀態,1表示已被探索,0表示尚未被探索
        {
            b[i]=1;//標記當前的b[i]已被探索
            a[level]=i;//記錄當前的節點值
            dfs(level+1);//進一步的搜尋
            b[i]=0
;//還原當前的b[i]元素被探索的狀態 } } }


數字型搜尋


全排列問題

題目描述

排列與組合是常用的數學方法。
先給一個正整數 ( 1 < = n < = 10 )
例如n=3,所有組合,並且按字典序輸出:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

輸入

輸入一個整數n( 1<=n<=10)

輸出

輸出所有全排列

每個全排列一行,相鄰兩個數用空格隔開(最後一個數後面沒有空格)

樣例輸入Copy

3

樣例輸出Copy

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
#include<bits/stdc++.h>
#include<queue>
using namespace std;
const int N=100;
typedef long long ll;
int n,a[10010],b[10010];
void print()
{
    for(int i=1;i<=n;i++)
    {
        printf("
%5d",a[i]); } cout<<endl; } void dfs(int level) { if(level==n+1) { print(); return; } for(int i=1;i<=n;i++) { if(b[i]==0) { b[i]=1; a[level]=i; dfs(level+1); b[i]=0; } } } int main() { cin>>n; dfs(1); }

【牛客】Factorial

1、暴力解題,程式碼略;

2、dfs解題(重點),萬物皆可搜,有點類似斐波那契遞迴

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e5+10;
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define T int t ;cin >> t;while(t--)
ll a[maxn];
ll dfs(ll n)
{
    if(n<=1)
    {
        return 1;
    }
    else
    {
        return dfs(n-1)*n;
    }
}
int main()
{
    T
    {
        ll n;
        scanf("%lld",&n);
        printf("%lld\n",dfs(n));
    }
}


地圖型搜尋


n皇后問題

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,y[100010],s,ans[100010];
bool check(int x)//剪枝,判斷兩點的位置\\
兩點的斜率的絕對值不得等於1;兩點不得在同一水平線上(包括同一行和同一列)
{
    for(int i=1;i<x;i++)//i本身就是指行號,y[i]表示對應的列號
    {
        if(abs(x-i)==abs(y[x]-y[i])||y[x]==y[i]||x==i)
        {
            return 0;
        }
    }
    return 1;
}
void dfs(int num)
{
    if(num>n)//越界處理
    {
        s++;
        return;
    }
    for(int i=1;i<=n;i++)
    {
        y[num]=i;//將當前的行號賦值給第num個皇后
        if(check(num))
            dfs(num+1);//進行下一步的搜尋
    }
}
int main()
{
    for(int i=1;i<=10;i++)
    {
        n=i;
        s=0;
        dfs(1);
        ans[i]=s;
    }
    while(~scanf("%d",&n)&&n)
        printf("%d\n",ans[n]);
}

POJ3083Children of the Candy Corn

左搜尋(Ldfs)+右搜尋(Rdfs)+最短路徑搜尋(bfs)

搜尋方位

左搜尋:

始終靠左搜尋,如果左邊是牆#,那就往上面搜尋;上面是牆#,那就往右邊搜尋;右邊是牆#則返回之前的位置,即往後搜尋。

右搜尋:

bfs最短路搜尋:

建立佇列,在一個點的周圍的同一層搜尋(這是與DFS的區別最大之處),用vis陣列標記是否被搜尋過

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=55;
char mp[41][41];
int vis[41][41];
int m,n,f,ans1,ans2;
int head_x,head_y,tail_x,tail_y;
int dir1[4][2]= {-1,0,1,0,0,1,0,-1};
struct node
{
    int x,y,step;
} head,tail;
bool judge(int xx,int yy)
{
    if(xx>=1&&xx<=m&&yy>=1&&yy<=n&&mp[xx][yy]!='#'&&vis[xx][yy]==0)
        return true;
    return false;
}
void dfs1(int xx,int yy,int step,int dir)//逆時針走法
{
    if(f==1)
        return;
    if(xx==tail_x&&yy==tail_y)
    {
        f=1;
        ans1=step;
        return;
    }
    if(dir==1)//右上左下
    {
        if(judge(xx+1,yy)) dfs1(xx+1,yy,step+1,4);
        if(judge(xx,yy-1)) dfs1(xx,yy-1,step+1,1);
        if(judge(xx-1,yy)) dfs1(xx-1,yy,step+1,2);
        if(judge(xx,yy+1)) dfs1(xx,yy+1,step+1,3);
    }
    else if(dir==2)//上左下右
    {
        if(judge(xx,yy-1)) dfs1(xx,yy-1,step+1,1);
        if(judge(xx-1,yy)) dfs1(xx-1,yy,step+1,2);
        if(judge(xx,yy+1)) dfs1(xx,yy+1,step+1,3);
        if(judge(xx+1,yy)) dfs1(xx+1,yy,step+1,4);
    }
    else if(dir==3)//左下右上
    {

        if(judge(xx-1,yy)) dfs1(xx-1,yy,step+1,2);
        if(judge(xx,yy+1)) dfs1(xx,yy+1,step+1,3);
        if(judge(xx+1,yy)) dfs1(xx+1,yy,step+1,4);
        if(judge(xx,yy-1)) dfs1(xx,yy-1,step+1,1);
    }
    else//右下上左
    {
        if(judge(xx,yy+1)) dfs1(xx,yy+1,step+1,3);
        if(judge(xx+1,yy)) dfs1(xx+1,yy,step+1,4);
        if(judge(xx,yy-1)) dfs1(xx,yy-1,step+1,1);
        if(judge(xx-1,yy)) dfs1(xx-1,yy,step+1,2);
    }
}
void dfs2(int xx,int yy,int step,int dir)
{
    if(f==1)
    {
        return;
    }
    if(xx==tail_x&&yy==tail_y)
    {
        f=1;
        ans2=step;
        return;
    }
    if(dir==1)
    {
        if(judge(xx-1,yy)) dfs2(xx-1,yy,step+1,2);
        if(judge(xx,yy-1)) dfs2(xx,yy-1,step+1,1);
        if(judge(xx+1,yy)) dfs2(xx+1,yy,step+1,4);
        if(judge(xx,yy+1)) dfs2(xx,yy+1,step+1,3);
    }
    else if(dir==2)
    {
        if(judge(xx,yy+1)) dfs2(xx,yy+1,step+1,3);
        if(judge(xx-1,yy)) dfs2(xx-1,yy,step+1,2);
        if(judge(xx,yy-1)) dfs2(xx,yy-1,step+1,1);
        if(judge(xx+1,yy)) dfs2(xx+1,yy,step+1,4);

    }
    else if(dir==3)
    {
        if(judge(xx+1,yy)) dfs2(xx+1,yy,step+1,4);
        if(judge(xx,yy+1)) dfs2(xx,yy+1,step+1,3);
        if(judge(xx-1,yy)) dfs2(xx-1,yy,step+1,2);
        if(judge(xx,yy-1)) dfs2(xx,yy-1,step+1,1);
    }
    else
    {
        if(judge(xx,yy-1)) dfs2(xx,yy-1,step+1,1);
        if(judge(xx+1,yy)) dfs2(xx+1,yy,step+1,4);
        if(judge(xx,yy+1)) dfs2(xx,yy+1,step+1,3);
        if(judge(xx-1,yy)) dfs2(xx-1,yy,step+1,2);
    }
}
int bfs()
{
    queue<node> q;
    while(!q.empty())
    {
        q.pop();
    }
    head.x=head_x,head.y=head_y,head.step=1;
    q.push(head);
    vis[head_x][head_y]=1;
    while(!q.empty())
    {
        head=q.front();
        q.pop();
        if(head.x==tail_x&&head.y==tail_y)
        {
            return head.step;
        }
        for(int i=0; i<4; i++)
        {
            tail.x=head.x+dir1[i][0];
            tail.y=head.y+dir1[i][1];
            if(judge(tail.x,tail.y))
            {
                tail.step=head.step+1;
                vis[tail.x][tail.y]=1;
                q.push(tail);
            }
        }
    }
    return 0;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(vis,0,sizeof vis);
        scanf("%d%d",&n,&m);
        for(int i=1; i<=m; i++)
        {
            for(int j=1; j<=n; j++)
            {
                scanf(" %c",&mp[i][j]);
                if(mp[i][j]=='S')
                {
                    head_x=i;
                    head_y=j;
                }
                if(mp[i][j]=='E')
                {
                    tail_x=i;
                    tail_y=j;
                }
            }
        }
        f=0;
        ans1=0;
        dfs1(head_x,head_y,1,1);
        f=0;
        ans2=0;
        dfs2(head_x,head_y,1,1);
        int ans3=bfs();
        printf("%d %d %d\n",ans1,ans2,ans3);
    }
}

棋盤問題

n表示棋盤的大小是n*n,m表示棋子的數量,結束dfs的條件就是當前的棋子數量大於等於m(因為初始的0就已經存在1顆棋子了)。

#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#define IO ios::sync_with_stdio(false), cin.tie(0)
typedef long long ll;
using namespace std;
const ll maxn=1e5+10;
char mp[100][100];
bool vis[100];
ll n,m,s;
void dfs(ll x,ll y)
{
    if(y>=m)
    {
        s++;
        return;
    }
    for(ll i=x; i<n; i++)
        for(ll j=0; j<n; j++)
        {
            if(vis[j]==false&&mp[i][j]=='#')
            {
                vis[j]=true;
                dfs(i+1,y+1);
                vis[j]=false;
            }
        }
}
int main()
{
    while(1)
    {
        scanf("%lld%lld",&n,&m);
        if(n==-1&&m==-1)
            break;
        memset(vis,0,sizeof vis);
        memset(mp,0,sizeof mp);
        for(ll i=0; i<n; i++)scanf("%s",mp[i]);
        s=0;
        dfs(0,0);
        cout<<s<<endl;
    }
}

Oil Deposit

#include <bits/stdc++.h>
using namespace std ;
typedef long long ll;
ll m,n;
char mp[110][110];
ll dir[8][2]= { {0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1} };//方向可以任意,當前方向見圖
void dfs(ll x,ll y)
{
    mp[x][y]='*';//把當前的@轉換成*,避免重複查詢
    for(ll i=0; i<8; i++)
    {
        ll xx=x+dir[i][0],yy=y+dir[i][1];
        if(xx>=1&&xx<=m&&yy>=1&&yy<=n&&mp[xx][yy]=='@')
        {
            dfs(xx,yy);
        }
    }
    return;//遞迴結束
}
int main()
{
    while(~scanf("%lld%lld",&m,&n)&&n&&m)
    {
        ll sum=0;
        for(ll i=1; i<=m; i++)
        {
            for(ll j=1;j<=n;j++)
            {
                cin>>mp[i][j];
                //scanf(" %c",&mp[i][j]);
                //兩種讀入方式均可,要注意的是,用scanf()讀入的話,需要在%c之前加入一個空格,這是專門用來吸收"\n"
            }
        }
        for(ll i=1; i<=m; i++)
        {
            for(ll j=1; j<=n; j++)
            {
                if(mp[i][j]=='@')
                {
                    dfs(i,j);
                    sum++;
                }
            }
        }
        cout<<sum<<endl;
    }
}

Red and Black

用dfs搜尋最長路,黑磚可走,紅磚不可走,@表示出發點,輸出最大黑磚數

#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
typedef long long ll;
ll m,n;
char mp[25][25];
ll dir[4][2]={ {-1,0},{1,0},{0,-1},{0,1} };
ll s;
void dfs(ll x,ll y)
{
    ll xx,yy;
    for(ll i=0;i<4;i++)
    {
        xx=x+dir[i][0];
        yy=y+dir[i][1];
        if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&mp[xx][yy]!='#')
        {
            s++;
            mp[xx][yy]='#';
            dfs(xx,yy);
        }
    }
}
int main()
{
    while(~scanf("%lld %lld",&m,&n)&&m&&n)
    {
        ll xx,yy;
        for(ll i=1;i<=n;i++)
        {
            for(ll j=1;j<=m;j++)
            {
                scanf(" %c",&mp[i][j]);
                if(mp[i][j]=='@')
                {
                    xx=i;
                    yy=j;
                }
            }
        }
        s=1;
        mp[xx][yy]='#';
        dfs(xx,yy);
        cout<<s<<endl;
    }
}

P1162 填塗顏色

建議從1開始讀入,因為這樣有一個好處,能夠建立起天然的下標為0的圍牆陣列,可以防止陣列下標小於0,以至於越界

dfs1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e6+10;
ll n;
ll mp[35][35];
ll vis[35][35];
ll dir[4][2]= { {-1,0},{1,0},{0,-1},{0,1} };
void dfs(ll x,ll y)
{
    if(x==0||y==0||x>n||y>n)
        return;
    for(ll i=0; i<4; i++)
    {
        ll xx=x+dir[i][0],yy=y+dir[i][1];
        if(mp[xx][yy]!=1&&xx>=1&&xx<=n&&yy>=1&&yy<=n&&!vis[xx][yy])
        {
            vis[xx][yy]=1;
            dfs(xx,yy);
        }
    }
}
int main()
{
    memset(vis,0,sizeof vis);
    memset(mp,0,sizeof mp);
    scanf("%lld",&n);
    for(ll i=1; i<=n; i++)
    {
        for(ll j=1; j<=n; j++)
        {
            cin>>mp[i][j];
        }
    }
    for(ll i=1;i<=n;i++)
    {
        if(mp[1][i]==0)
            dfs(1,i);
        if(mp[i][1]==0)
            dfs(i,1);
        if(mp[n][i]==0)
            dfs(n,i);
        if(mp[i][n]==0)
            dfs(i,n);
    }
    for(ll i=1; i<=n; i++)
    {
        for(ll j=1; j<=n; j++)
        {
            if(j>1)
                cout<<' ';
            if(mp[i][j]!=1&&!vis[i][j])
                mp[i][j]=2;
                cout<<mp[i][j];
        }
        cout<<endl;
    }
}

dfs2

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mp[35][35];
ll n;
ll dir[4][2]={ {-1,0},{1,0},{0,-1},{0,1} };
void dfs(ll x,ll y)
{
    mp[x][y]=3;
    for(ll i=0;i<4;i++)
    {
        ll xx=x+dir[i][0],yy=y+dir[i][1];
        if(xx>=0&&yy>=0&&xx<=n+1&&yy<=n+1&&mp[xx][yy]==0)
        {
            dfs(xx,yy);
        }
    }
}
int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
    {
        for(ll j=1;j<=n;j++)
        {
            cin>>mp[i][j];
        }
    }
    dfs(0,0);
    for(ll i=1;i<=n;i++)
    {
        for(ll j=1;j<=n;j++)
        {
            if(j>1)
            {
                cout<<' ';
            }
            if(mp[i][j]==3)
            {
                mp[i][j]=0;
            }
            else if(mp[i][j]==0)
            {
                mp[i][j]=2;
            }
            cout<<mp[i][j];
        }
        cout<<endl;
    }
}

-------------------------------------------------------------------------------------------------------------