深度優先搜索(DFS)淺談

一,定義

        通俗說DFS就是有路就走,一條道走到黑,走不通就回上一個分支的再選路,再不行就回上上個分支點......依次類推,最終找到一條通路。

 

例1:給定N個整數A1,A2 .....,判斷可否從中選出若干數,使它們的和恰好爲K。

         思路:從第一個數開始,按順序決定每個數加還是不加,當對這個N個數全部決定完之後判斷它們的和是不是K就可以。

                   假設a = {1,2,4,7} k = 13; 圖示:

代碼表示:

#include<iostream>
using namespace std;

//原始數據 1,2,4,7;目標和13,如果有解則輸出OK 
int a[4] = {1,2,4,7};
int k = 13;
int n = 4;

//假設已選則了前i項,當前的值爲sum
bool dfs(int i,int sum) {
	//如果已經選擇完了
	if(i==n) {
		//如果和sum與k相等,返回true
		if(sum==k) {
			return true;
		}
		return false;
	}
	//不選擇a[i]的情況
	if(dfs(i+1,sum)) {
		return true;
	}
	//加上a[i]的情況
	if(dfs(i+1,sum+a[i])) {
		return true;
	}
	//即怎麼樣都不能湊成k
	return false;
}

int main() {
	if(dfs(0,0)) {
		cout<<"OK"<<endl;
	} else {
		cout<<"NO"<<endl;
	}
	return 0;

}

          分析:當前這個算法確實可行,但應該注意,這裏舉出的僅僅是一個規模非常小的問題,即使這樣在最糟的情況下它最多需32步才能得到最終結果;當問題規模稍大時,其時複復度O(2 ^ N)極容易超限;同時,在上題中我們無法獲得是哪幾個元素湊成了K的解答,爲此,我們對上述代碼進行一點點優化。

優化代碼:

#include<stdio.h>
int a[4] = {1,2,4,7};             //原始數據 1,2,4,7;目標和13,如果有解則輸出OK
int k = 13;
int n = 4;
int b[4];                         //標記數組

bool dfs(int x,int sum)  {
	if(sum>k) {               //剪枝,避免不必要的操作
		return false;
	}
	if(x==n) {                //如果前n項計算過了,返回sum=k是否相等
		return sum==k;
	}
	if(dfs(x+1,sum)) {
		b[x]=0;           //如果不加上a[x]的情況,b[x]標記爲0
		return true;
	}
	if(dfs(x+1,sum+a[x])) {
		b[x]=1;           //如果加上a[x]的情況,b[x]標記爲1
		return true;
	}
	return false;
}

int main() {
	if(dfs(0,0)) {
		printf("YES\n");
		for(int i=0; i<n; i++) {
			if(b[i]) {
				printf("%d ",a[i]);
			}
		}
		printf("\n");
	} else {
		printf("NO\n");
	}
	return 0;
}

運行結果:

       上文中提到了剪枝這一概念,顧名思義,在DFS中,有時早已明確的知道無論怎麼選都不會存在解,在這種情況下不再繼續搜索而是略過,這種方法稱爲剪枝。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章