挑戰程式設計競賽page.30思路:從a0開始按順序決定每個數字加還是不加,在全部n個數都決定後再判斷它們的和是不是為k即可。因為狀態數是2n,所以複雜度為o(2n)。
int n,a[maxn]
,k;bool
dfs(
int dep,
int sum)
void
solve()
深度優先搜尋從最開始的狀態出發,遍歷所有可以到達的狀態,由此可以對所有的狀態進行操作,或者列舉出所有的狀態。
#include
#include
#include
using
namespace std;
const
int maxn=
1005
;char g[maxn]
[maxn]
;int n,m;
void
dfs(
int x,
int y)
}return;}
intmain()
int ans=0;
for(
int i=
0;i}printf
("%d\n"
,ans)
;return0;
}
寬度優先搜尋(bfs,breadth-first search)也是搜尋的手段之一。它與深度優先搜尋類似,從某個狀態出發探索所有可以到達的狀態。
與深度優先搜尋的不同支出在於搜尋的順序,寬度優先搜尋總是先搜尋距離處使狀態近的狀態。對於同乙個狀態,寬度優先搜尋只經過依次,因此複雜度為o(狀態數 x 轉移的方式)。
深度優先搜尋隱式的利用了棧進行計算,而寬度優先搜尋則利用了佇列,搜尋時首先將初始狀態記錄到佇列裡,此後從佇列的前端不斷取出狀態,直到從該狀態中把所有能到達的狀態加入佇列中。如此往復,直到佇列被取空或找到了問題的解。
程式挑戰設計競賽page 34
const
int inf=
1e8;
typedef pair<
int,
int> p;
int d[maxn]
[maxn]
;char g[maxn]
[maxn]
;int n,m;
int sx,sy,ex,ey;
//起點和終點
int dx=
,dy=
;int
bfs()}
que.
push(p
(sx,sy));
d[sx]
[sy]=0
;while
(!que.
empty()
)}}return inf;
}void
solve()
寬度優先搜尋會把狀態逐個加入佇列,通常需要與狀態數成正比的記憶體空間。反之,深度優先搜尋是與最大的遞迴深度成正比的。一般與狀態數相比,遞迴的深度並不會太大。所以可以認為深度優先搜尋更加節省記憶體。
此外,也有採用與寬度優先搜尋類似的狀態轉移順序,並且注重節約記憶體占用的迭代加深深度優先搜尋(iddfs)。iddfs是一種再最開始將深度優先搜尋的遞迴次數限制在1次,在找到解之前不斷增加遞迴深度的方法。
雖然生成可行解空間多採用深度優先搜尋,但在狀態空間比較特殊時其實可以很簡短地實現。比如,c++的標準庫中提供了next_permutation這一函式,可以把n個元素的共n!種不同的排列生成出來,又或者,通過使用位運算,可以列舉從n個元素中取出k個共cn
k狀態或是某個集合中的全部子集等。
bool used[maxn]
;int perm[maxn]
;//生成0到n-1的n!中排列
void
permutation
(int pos,
int n)
for(
int i=
0;i}#include
//即使有重複的元素也會生成所有的排列
//next_permutation是按照字典序來生成下乙個排列的
void
permutation()
dowhile
(next_permutation
(perm2,perm2+n));
}
挑戰程式設計競賽(第二章 2 4 資料結構)
expedition include include include include using namespace std const int max 10001 int n,l,p,sd,sf struct node bool cmp1 node a,node b struct cmp2 nod...
第二章學習筆記
在c 中,陣列下標從0開始,而不是1.c 不支援陣列的抽象,也不支援對整個陣列的操作。在c 中,物件可以靜態分配 即編譯器在處理程式源 時分配,也可以動態分配 即程式執行時,用執行時刻庫函式來分配。靜態與動態記憶體分配的兩個主要區別是 1 靜態物件是有名字的變數,可以直接對你進行操作。而動態物件是沒...
第二章學習筆記
ansi c 有翻譯和執行兩種環境,且不必在一台機器上,例如交叉編譯器 cross compiler 作業系統也是如此 freestanding environment 翻譯 將源 轉換為可執行機器指令 執行 實際執行 翻譯經過以下階段 形成的目標檔案字尾可能在不同系統下不同,如 o obj cc ...