前言:
學習算法時,一個關鍵的問題是什麼時候來使用它。在一些搜索問題中,使用普通的DFS可能會讓你把時間浪費在深度非常大而且答案不是最優的搜索過程上,甚至有的時候DFS搜索的深度是無窮的,而BFS雖說理論上可以避免這種情況,卻又無法滿足題目的某些需求,或者無法實現。仔細思考一下這個例子,它有着兩個特徵:一是它是個最優解問題,二是最優的答案深度最小,如右圖:
但是我們的答案有三個,若我們要ans3這個答案,那麼DFS和BFS都是不滿足的,so我們引入迭代加深搜索來解決這個問題。
概念:
》 迭代加深搜索,實質上就是限定下界的深度優先搜索。即首先允許深度優先搜索K層搜索樹,若沒有發現可行解,再將K+1後重復以上步驟搜索,直到搜索到可行解。
》 在迭代加深搜索的算法中,連續的深度優先搜索被引入,每一個深度約束逐次加1,直到搜索到目標爲止。
》 迭代加深搜索算法就是仿廣度優先搜索的深度優先搜索。既能滿足深度優先搜索的線性存儲要求,又能保證發現一個最小深度的目標結點。
》 從實際應用來看,迭代加深搜索的效果比較好,並不比廣度優先搜索慢很多,但是空間複雜度卻與深度優先搜索相同,比廣度優先搜索小很多,在一些層次遍歷的題目中,迭代加深不失爲一種好方法!
那麼我們就開始例題吧。
題目描述:
An addition chain for n is an integer sequence <a0, a1,a2,...,am> with the following four properties:
- a0 = 1
- am = n
- a0 < a1 < a2 < ... < am-1 < am
- For each k (1 <= k <= m) there exist two (not necessarily different) integers i and j (0 <= i, j <= k-1) with ak = ai + aj
You are given an integer n. Your job is to construct an addition chain for n with minimal length. If there is more than one such sequence, any one is acceptable.
For example, <1, 2, 3, 5> and <1, 2, 4, 5> are both valid solutions when you are asked for an addition chain for 5.
輸入;
The input will contain one or more test cases. Each test case consists of one line containing one integer n (1 <= n <= 100). Input is terminated by a value of zero (0) for n.
輸出;
For each test case, print one line containing the required integer sequence. Separate the numbers by one blank.
輸入樣例:
5
7
12
15
77
0
輸出樣例:
1 2 4 5
1 2 4 6 7
1 2 4 8 12
1 2 4 5 10 15
1 2 4 8 9 17 34 68 77
總之就是:
已知一個數列a0,a1,……,am(其中a0=1,am=n,a0<a1<……<am-1<am)。
對於每個k,需要滿足ak=ai+aj(0 ≤ i,j ≤ k-1,這裏i與j可以相等)。
現給定n的值,要求m的最小值(並不要求輸出)。
及這個數列每一項的值(可能存在多個數列,只輸出任一個滿足條件的就可以了)(但其實不然)。
思路分析:
此是來自GM的題解:
首先可以求出最少需要幾個元素可以達到n。按照貪心的策略,對於每個元素的值,都選擇讓它等於一個數的兩倍,即對於每個Ai = Ai-1 + Ai-1, 當Ai>=n時就跳出循環,得到最少元素個數。然後從最少步數開始迭代加深搜索。 最後再用上一些減枝技巧即可。
而現在是主要講IDDFS。
首先,當長度與規定深度相同時,我們就要判斷數列末項是否相同,如果相同就是答案。
然後從數列的前項裏求最好的方法。(這裏一定要從後往前找,不然過不了)。
然後還有一個期望函數,若果用最大的數都無法得到答案,那麼就返回。
代碼實現:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,ans[105];
bool f;
void dfs(int x,int de)
{
if(f)
return;
if(x==de)
{
if(ans[x]==n)
f=1;
return;
}
for(int i=x;i>=0;i--)
{
for(int j=i;j<=x;j++)
if(ans[i]+ans[j]>ans[x]&&ans[i]+ans[j]<=n)
{
int sum=ans[i]+ans[j];
for(int k=x+2;k<=de;k++)
sum*=2;
if(sum<n)
continue;
ans[x+1]=ans[i]+ans[j];
dfs(x+1,de);
if(f)
return;
}
}
}
int main()
{
while(scanf("%d",&n)!=-1)
{
if(n==0)
return 0;
memset(ans,0,sizeof(ans));
f=0;
ans[0]=1;
int m=1,depth=0;
while(m<n)
{
m*=2;
depth++;
}
while(1)
{
dfs(0,depth);
if(f)
break;
depth++;
}
printf("%d",ans[0]);
for(int i=1;i<=depth;i++)
printf(" %d",ans[i]);
printf("\n");
}
}