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