题目意思: 给定一个正数 n ,要求找到一个最短序列满足 一下4个条件
- 1 a0 = 1
- 2 am = n
- 3 a0 < a1 < a2 < ... < am-1 < am
- 4 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;
解题思路: (uva赤裸裸的超时了,其它poj zju bnuoj都是几十毫秒过得,先贴上来,可能uva数据n很大然后我的程序就挂了,等我想通了再来更新代码)。
这是一道隐式树问题,没有给我们具体的解空间树,我们需要自己想象。我们知道如果我们对每一个状态都取搜索,结果必然超时。
那么我们想到剪枝,方法就是在递归的时候加上一些判断的条件,比如我们搜索是对这颗解空间树搜索,那么如果碰到那些没有用的状态我么可以直接舍去,还有对于当前的长度如果大于已有的最小值也可以直接return
代码:
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <vector> #include <cstdio> #include <stack> #include <list> using namespace std; #define MAXN 10005 int n , Min; int ans[MAXN] , temp[MAXN];//ans存储最后的结果,temp存储每一个状态 //递归处理 void dfs(int pos) { if(pos >= Min)//如果当前的长度大于或等于Min直接return return; else{ for (int i = 0; i < pos; i++) {//枚举每一种可能的状态 int t = temp[i] + temp[pos-1]; if(t == n){//t = n说明到达末尾 if(Min > pos){//判断最小值以及更新ans数组 Min = pos; for(int k = 0 ; k < Min ; k++) ans[k] = temp[k]; } return; } if(t < n){//小于n进行dfs temp[pos] = t;//t存入temp[pos] dfs(pos+1); temp[pos] = 0;//回溯回来的状态恢复 } } } } //主函数 int main() { while (scanf("%d", &n) && n) { memset(ans, 0, sizeof (ans)); memset(temp, 0, sizeof (temp)); Min = MAXN; if (n > 1) {//n大于1才搜索 temp[0] = 1; ans[0] = 1; dfs(1); printf("1"); for (int i = 1; i < Min; i++) printf(" %d", ans[i]); printf(" %d\n", n); } else//你等于1直接输出 printf("1\n"); } return 0; }