DFS深度优先搜索(入门)

DFS入门(递归写法)

这两天在学习深度优先搜索(DFS),感觉DFS比BFS难,一开始主要是标记搞不清楚。DFS在回溯时要取消原先的标记,而BFS不存在回溯也就不存在取消标记这一问题。DFS可以用递归来写,也可以用栈来写。既然是入门,那我就从递归开始学起。下提供一个PPT链接,不会的时候就反复看里面雪人的运动情况:http://www.docin.com/p-542536008.html

下面看两到例题:

例1:http://acm.fafu.edu.cn/problem.php?id=1593

 

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

 

例2:http://acm.fafu.edu.cn/problem.php?id=1072

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

 

    原文作者:DFS
    原文地址: https://blog.csdn.net/coding_or_dead/article/details/52326519
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞