題目連結:
UVA :http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=470
POJ : http://poj.org/problem?id=2248
類型: 回溯, 迭代加深搜尋, 減枝
原題:
An addition chain for n is an integer sequence with
the following four properties:
- a0 = 1
- am = n
- a0<a1<a2<...<am-1<am
- For each k ( ) there exist two (not neccessarily different) integers i and j ( )
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.
範例輸入:
571215770
範例輸出:
1 2 4 51 2 4 6 71 2 4 8 121 2 4 5 10 151 2 4 8 9 17 34 68 77
題目大意:
給一個數字n, 然後輸出一個元素個數最少的從1到n的序列(可能有多種方案,輸出其中一種即可)。
其中對於第k個數Ak, 它的值等於Ai+Aj( )
。
分析與總結:
這一題是典型的迭代加深搜尋+減枝的題目。
迭代加深的搜尋(IDS,Iterative Deepening Search):
迭代加深搜尋,實質上就是限定下界的深度優先搜尋。即首先允許深度優先搜尋K層搜尋樹,若沒有發現可行解,再將K+1後重複以上步驟搜尋,直到搜尋到可行解。
在迭代加深搜尋的演算法中,連續的深度優先搜尋被引入,每一個深度約束逐次加1,直到搜尋到目標為止。
迭代加深搜尋演算法就是仿廣度優先搜尋的深度優先搜尋。既能滿足深度優先搜尋的線性儲存要求,又能保證發現一個最小深度的目標結點。
從實際應用來看,迭代加深搜尋的效果比較好,並不比廣度優先搜尋慢很多,但是空間複雜度卻與深度優先搜尋相同,比廣度優先搜尋小很多。
對於這一題,首先可以求出最少需要幾個元素可以達到n。按照貪心的策略,對於每個元素的值,都選擇讓它等於一個數的兩倍,即對於每個Ai = Ai-1 + Ai-1, 當Ai>=n時就跳出迴圈,得到最少元素個數。
然後從最少步數開始迭代加深搜尋。 然後再用上一些減枝技巧即可。
// 深度迭代搜尋+減枝 Time: UVa 0.012s POJ: 0MS#include<iostream>#include<cstdio>#include<cstring>using namespace std;int n,ans[100];bool flag;void dfs(int cur, int depth){ if(flag) return; if(cur==depth){ if(ans[cur]==n) flag=true; return ; } for(int i=0; i<=cur; ++i){ for(int j=i; j<=cur; ++j)if(ans[i]+ans[j] > ans[cur] && ans[i]+ans[j]<=n ){ // 這裡也進行減枝 // 下面這個減枝至關重要!!如果從當前一直往下都是選擇最大的策略還是不能達到n,跳過 bool ok = false; int sum=ans[i]+ans[j]; for(int k=cur+2; k<=depth; ++k) sum *= 2; if(sum < n) continue; ans[cur+1] = ans[i]+ans[j]; dfs(cur+1, depth); if(flag)return; } }}int main(){ while(scanf("%d", &n),n){ memset(ans, 0, sizeof(ans)); ans[0] = 1; flag = false; // 計算出至少需要多少步 int m=1, depth=0; while(m<n){ m *= 2; depth++; } // 從最少步開始進行迭代加深搜尋 while(true){ dfs(0, depth); if(flag) break; depth++; } printf("%d", ans[0]); for(int i=1; i<=depth; ++i) printf(" %d", ans[i]); printf("\n"); } return 0;}
—— 生命的意義,在於賦予它意義。
原創 http://blog.csdn.net/shuangde800 , By D_Double (轉載請標明)