题目地址:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=470
题目描述:
Addition Chains |
An addition chain for n is an integer sequence with the following four properties:
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.
Hint: The problem is a little time-critical, so use proper break conditions where necessary to reduce the search space.
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题意:
a[0]=1 a[m]=n,a序列为严格递增序列, 对于任意的下标k在[1,m]内 都存在 1 <= j <= i <= k-1 使得 a[i]+a[j]=a[k],找出m最小的符合条件的序列,即长度最小的序列。
题解:
迭代深搜+剪枝
刚开始仅仅是DFS+剪枝,结果怎么剪都不行,过个300的数据就卡半天。无奈解题报告,说是迭代深搜。
迭代深搜其实就是DFS的变种(变种特别特别多,灵活变种与组合),即是一种限定了搜索深度的DFS,然后利用已限定的深度可以做各种各样的剪枝和其他操作,而整体模式更像是BFS,该深度没有答案,则深度+1,就像是一层一层的广度搜索。其实带有BFS思想的DFS以前也是写过的,也可以说算是这么一种。
对于剪枝:
1、当前深度要填的数 肯定来自于它前几位中,较大的两位组成,且其和 要小于等于末端值n 又要大于前一位的值(序列严格递增)。即 a[k-1] < a[i]+a[j] <= n
2、对于当前要填的值 temp,由于已经确定了深搜的深度,那么 我们按最大的取值(i,j都取前一位,即a[k-1]*2) 延伸到 最大深度时候的temp,如果其值都比n小(能取的最大值都比n小),意味着在这趟搜索中它永远不可能达到n,所以剪掉这支。
代码:
/* use IDS I have not any other way to solve it */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; int a[1000]={1};//a[0]=1 int n=0; int depth=0; int flag=0;//find the min length /*DFS the sequence place schedule*/ int DFS(int len,int depth) { if(flag) return(0); if(len==depth&&a[len-1]==n) { flag=1; return(0); } else { int i=0,j=0; for(i=len-1;i>=0;i--) { for(j=i;j>=0;j--) { if(a[i]+a[j]<=n&&a[i]+a[j]>a[len-1])//prune,the sequence is strictly increasing { a[len]=a[i]+a[j]; //prune,IDS prune int temp=a[len]; int k=0; for(k=len+1;k<=depth;k++) { temp*=2; } if(temp<n) { continue; } DFS(len+1,depth); if(flag) return(0); } } } } return(0); } /*for test*/ int test() { //find the law or formula int i=300; for(i=1;i<=300;i++) { printf("%d\n",i ); } return(0); } /*main process*/ int MainProc() { while(scanf("%d",&n)!=EOF&&n>0) { //init a[0]=1; depth=0; int temp=1; while(temp<n) { depth++; temp*=2; } depth++;//at least depth,temp>=n so depth++,it at least (not must) be this area,not the tem<n area,depth is same as len flag=0; while(!flag) { DFS(1,depth); if(!flag) { depth++; } } //out printf("%d",a[0] ); int i=0; for(i=1;i<=depth-1;i++) { printf(" %d",a[i] ); } printf("\n"); } return(0); } int main(int argc, char const *argv[]) { /* code */ //test(); MainProc(); return 0; }