當答案的層數較低,並且搜尋的分支較多時,如果直接搜尋會消耗很多時間。這時候可以進行多次搜尋,每次搜尋可以限制乙個深度,如果我們在當前深度下搜尋不到答案,就增加深度限制,重新搜尋一邊答案,這樣「迭代」且「加深」的過程稱為迭代加深。但他的缺點也很明顯,每次需要重新搜尋一遍,所以在答案的層數比較深的時候不建議使用。
【例題】addition chains (poj2248)
需要求乙個長度(長度為m)最小的序列
a a
滿足 1、
a[1]
=1' role="presentation">1、a
[1]=
11、a
[1]=
12、a
[m]=
m 2、a
[m]=
m3、a
[1]2]
<..
...a
[m−1
]m]3 、a
[1
#include
#include
#include
#include
using
namespace
std;
typedef
long
long ll;
const
int inf=2147483647;
ll bin[40];
ll f[40],ed;
bool half=false;
int cnt,minn;
mapint>s;//到now這個狀態需最少要多少步,折半後第二次加上第一次的值
void dfs(int x,ll now,int step)
else
//過半,看看now和其他合併能否到達最終狀態
}return;
}dfs(x+1,now^f[x],step+1);
dfs(x+1,now,step);
}int main()
minn=inf;
half=false;cnt=n/2; dfs(1,0,0);
half=true; cnt=n; dfs(n/2+1,0,0);
printf("%d\n",minn);
return
0;}【例題】送禮物(tyvj1340)
在n個數中選若干個數,使得他們加起來小於等於w且最接近w,輸出這個最接近w的值。
( n<=45 w<=2^31-1)
可以看到w是很大的,所以不用揹包來做。
搜尋的話,對於乙個物品,樸素的有選和不選兩種選擇,那麼這樣的複雜度是o(
2n) o(2
n)
,但如我們上面所說,指數級複雜度如果折半可以接受的話,可以考慮雙向搜尋。我們發現o(
222+2
23)o (2
22+223
)是可以接受的,所以我們可以考慮折半搜尋。
首先,我們第一遍搜尋出前一半數中選出若干個可以達到的0~w之間的所有重量值,把他們存放在乙個有序陣列a中。
然後,第二遍在後一半選出若干個數,記錄他們的重量和now,對於乙個重量和now在a中二分查詢<=w-now中最大的乙個t,然後用t+now更新答案。
#include
#include
#include
#include
#include
#include
using
namespace
std;
typedef
long
long ll;
const
int n=50;
const
int inf=int_max;
int w;
int n,a[n];
int a[1
<<25],tmp=0;
int cnt;
int maxx;
bool half;
int cmp(int a,int b)
int erfen(int val)
else
r=mid-1;
}return ans;
}void dfs(int x,int now)
return;
}if((ll)now+a[x]<=w) dfs(x+1,now+a[x]);
dfs(x+1,now);
}int main()
迭代加深搜尋
深度優先搜尋每次選定乙個分支,然後往下搜尋,直到遞迴邊界 才回溯。這種策略有一點缺陷,那就是當搜尋樹的分支數目特別 多,並且答案在某個較淺的節點上,如果dfs在一開始就選錯了分 支,那就會在沒有答案的深層次浪費時間 當搜尋樹規模隨著層次的深入增長很快,並且能 夠確保答案在乙個較淺的節點上時,就可以使...
迭代加深搜搜尋
對於可以用回溯法求解但解答樹的深度沒有明顯上限的題目,可以考慮使用迭代加深搜尋。經典問題 埃及分數問題 給出乙個分數,比如19 45,把它寫成若干個形如1 ri的分數的和的形式,比如19 45 1 5 1 6 1 18,要求分母不能重複使用並且使用的分數的個數最少。如果有多組個數相同的解,最後的分數...
IDDFS迭代加深搜尋
includeusing namespace std const int maxn 10 int n,a maxn bool ans sort return true int h bool dfs int d,int maxd return false int solve return max an...