1. 程式人生 > >深度優先搜尋(DFS)的奇偶剪枝

深度優先搜尋(DFS)的奇偶剪枝

今天進行到DFS&&BFS&&活動網路問題。BFS和DFS可以解決很多有趣的問題,而BFS和DFS本身就有很多優化、變形。對於對於優化最常見的莫過於剪枝了,而對於搜尋剪枝,最常見的也就是奇偶剪枝。

先看沒有剪枝和剪枝之後的效果:

為什麼剪枝

因為DFS和BFS可以是認為樹形搜尋的。因此,他們的搜尋軌跡可以生成出深度優先生成樹和廣度優先生成樹,詳情見: 圖的連通性

如果我們在生成樹的過程中(就是查詢過程中),發現並確定一個分支不可能找到解,那麼我們就把這個分支剪掉,以節省時間。這就是剪枝。

奇偶剪枝

首先我們要知道一個前提:

奇數 + 偶數 = 奇數
偶數 + 偶數 = 偶數

那麼,也就可以推出:

偶數 = 奇數 - 奇數

偶數 = 偶數 - 偶數

假設有這麼一個地圖:

我們可以發現一個規律,從其中任意一個0到任意一個0需要偶數步,而其中任意一個1到任意一個0需要奇數步。

如果我們每一步的消耗時間是相同的,那麼,需要用時和最短的步數必須需要同奇偶才能到達,否者不會到達。

為了方便描述,我們假設我們在(sx,sy)的位置,需要消耗t時到達(ex,ey)。

那麼不管我們怎麼繞圈,如果 t-[abs(ex-sx)+abs(ey-sy)] 結果為非偶數(奇數),則無法在t步恰好到達。

因此,這樣我們就可以在搜尋過程中,實時判斷現在剩下的時間和現在位置到目的地最短距離是否同奇偶,如果不是,那麼就沒有必要搜尋下去了。

骨頭問題

再回到ZOJ2110,這個題用到了奇偶剪枝,並且還有一種搜尋前優化,就是如果所有狗狗能走的位置(所有的地圖位置的個數減去障礙物的個數)小於規定時間,直接列印NO(就是狗狗根本跑不開,就不用搜索了)。

程式碼:

#include <iostream>
#include <cstring>
#include <cmath>

using namespace std;

char mp[10][10];
int bj[10][10];
int chx[] = {0,1,0,-1};
int chy[] = {1,0,-1,0};
int n,m,t;
int ex,ey;
int tf;

void dfs(int x,int y,int tim)
{
    if(x < 0 || y < 0 || x >= n || y >= m)
        return ;

    if(tim == t && x == ex && y == ey)
    {
        cout << "YES" << endl;
        tf = 1;
        return ;
    }

    int tmp = (t - tim) - fabs(x - ex) - fabs(y - ey);

    if(tmp < 0 || tmp % 2)
        return ;

    for(int i = 0; i < 4;i++)
    {
        if(mp[x + chx[i]][y + chy[i]] != 'X')
        {
            mp[x + chx[i]][y + chy[i]] = 'X';
            dfs(x + chx[i],y + chy[i],tim + 1);
            if(tf)
                return ;
            mp[x + chx[i]][y + chy[i]] = '.';
        }
    }
}

int main()
{
    while(cin >> n >> m >> t,n)
    {
        tf = 0;
        memset(bj,-1,sizeof(bj));
        for(int i = 0;i < n;i++)
            cin >> mp[i];

        int x,y;

        for(int i = 0;i < n;i++)
        {
            int j;
            for(j = 0;j < m;j++)
                if(mp[i][j] == 'S')
                {
                    x = i;
                    y = j;
                    break;
                }
            if(j < m)
                break;
        }

        for(int i = 0;i < n;i++)
        {
            int j;
            for(j = 0;j < m;j++)
                if(mp[i][j] == 'D')
                {
                    ex = i;
                    ey = j;
                    break;
                }
            if(j < m)
                break;
        }

        mp[x][y] = 'X';
        dfs(x,y,0);

        if(!tf)
            cout << "NO" << endl;
    }
    return 0;
}

歡迎到微信裡去當吃瓜群眾