1. 程式人生 > >DFS深度優先搜尋(入門)

DFS深度優先搜尋(入門)

DFS入門(遞迴寫法)

這兩天在學習深度優先搜尋(DFS),感覺DFS比BFS難,一開始主要是標記搞不清楚。DFS在回溯時要取消原先的標記,而BFS不存在回溯也就不存在取消標記這一問題。DFS可以用遞迴來寫,也可以用棧來寫。既然是入門,那我就從遞迴開始學起。下提供一個PPT連結,不會的時候就反覆看裡面雪人的運動情況:http://www.docin.com/p-542536008.html

下面看兩到例題:

Description:

現給定一個含有n個元素的陣列A,要求:從這n個數中選擇一些數,這些數的和恰好為k

Input:

多組測試資料。第一行為n(1<=n<=20) 第二行為n個整數,每個數的範圍為(-10^8≤A[i]≤10^8) 第三行為整數k(-10^8≤k≤10^8).

Output:

如果能夠達到目的,輸出”Of course,I can!”; 否則輸出”Sorry,I can’t!”.

Sample Input:

4

1 2 4 7

13

4

1 2 4 7

15

Sample Output:

Of course,I can!

Sorry,I can't!

看到這種題,我首先想到了窮舉,而DFS又經常用於窮舉,那我們就用DFS來解這道題。

假如n = 4,目標值k = 13,4個數分別為1 2 4 7則:

①我們選1,1 < 13,繼續選;

②我們選1 2,1+2 <13,繼續選;

③我們選1 2 4,1+2+4 < 13,繼續選;

④我們選1 2 4 7,1+2+4+7 > 13,7不選;

其實‚中的2我們也可以不選,直接往下選,那就變成

我們選1 4 ,2不選,1+4 < 13,繼續選;

⑤我們選1 4 7,2不選,1+4+7 < 13

⑥同樣的,①中我們可以不選1,則:

我們選2,不選1,2 < 13,繼續選;

我們選2 4,不選1,2+4 < 13,繼續選;

我們選2 4 7,不選1,2+4+7 = 13 結束。

下面是原始碼:

#include<cstdio>
int n,i,k,sum,YES;
int a[25],vis[25];
bool DFS(int i,int sum)
{
    if(i < n && !vis[i])
    {
        vis[i] = 1;         //走過,標記1
        if(sum+a[i] == k)
            return YES=1;   //找到目標值
        else if(sum+a[i] < k)
        {
            DFS(i+1,sum);          //sum加a[i]後繼續往下找
            DFS(i+1,sum+a[i]);   //sum不加a[i]後繼續往下找
        }
        else
            DFS(i+1,sum);    //不加a[i]繼續找
        vis[i] = 0;     //回溯時取消標記
    }
    return YES;
}
int main(void)
{
    while(~scanf("%d",&n))
    {
        for(i = 0; i < n; i++)  //輸入n個數字
            scanf("%d",&a[i]);
        scanf("%d",&k); YES = 0;//輸入目標值k,初始化YES
        for(i = 0; i < n; i++)
            vis[i] = 0;//初始化vis陣列
        DFS(0,0);
        if(YES) puts("Of course,I can!");
        else puts("Sorry,I can't!");
    }

    return 0;
}


Description:

問題很簡單,給你n個正整數,求出這n個正整數中所有任選k個相乘後的和。

Input:

輸入有兩行,第一行是兩個整數n和k,其中1<=k<=n<=10。接下去一行就是n個正整數,保證最後結果用long即可儲存。

Output:

輸出只有一個正整數,為最後的和。

Sample Input:

4 2

1 2 3 4

Sample Output:

35

這題其實和上一道題沒有多大區別,如果上一題學會了,可以拿這題練練手。

下面直接貼出原始碼:

#include<cstdio>
#include<cstring>
int n,k;__int64 sum = 0;
int a[15],vis[15];
void DFS(int i,int cnt,int sm)//i為陣列元素下標,sm為cnt個數字的乘積
{
    if(cnt == k) {sum = sum + sm; return ;}
    if(i >= n) return ;
    if(!vis[i])
    {
        vis[i] = 1;
        DFS(i+1,cnt+1,sm*a[i]); //a[i]被選
        DFS(i+1,cnt,sm);        //a[i]不選
        vis[i] = 0;
    }
    return ;
}
int main(void)
{
    memset(vis,0,sizeof(vis));
    scanf("%d%d",&n,&k);
    for(int i = 0; i < n; i++)
        scanf("%d",&a[i]);
    //for(int i = 0; i <= n-k; i++)//i到n-k後,之後的數字個數肯定不足k個
        DFS(0,0,1);
    printf("%I64d\n",sum);

    return 0;
}