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