题目地址:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=470
题目描述:
Addition Chains
Addition Chains |
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.
Input Specification
The input file will contain one or more test cases. Each test case consists of one line containing one integer n ( ). Input is terminated by a value of zero (0) for n .Output Specification
For each test case, print one line containing the required integer sequence. Separate the numbers by one blank.
Hint: The problem is a little time-critical, so use proper break conditions where necessary to reduce the search space.
Sample Input
5 7 12 15 77 0
Sample Output
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 pruneint 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 formulaint 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){//inita[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 lenflag=0;while(!flag){DFS(1,depth);if(!flag){depth++;}}//outprintf("%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;
}