AcWing170加成序列(bfs || dfs+迭代加深)

题目如下

满足如下条件的序列X(序列中元素被标号为1、2、3…m)被称为“加成序列”:

1、X[1]=1

2、X[m]=n

3、X[1]

4、对于每个 k(2≤k≤m)都存在两个整数 i 和 j (1≤i,j≤k−1,i 和 j 可相等),使得X[k]=X[i]+X[j]。

你的任务是:给定一个整数n,找出符合上述条件的长度m最小的“加成序列”。

如果有多个满足要求的答案,只需要找出任意一个可行解。

输入格式
输入包含多组测试用例。

每组测试用例占据一行,包含一个整数n。

当输入为单行的0时,表示输入结束。

输出格式
对于每个测试用例,输出一个满足需求的整数序列,数字之间用空格隔开。

每个输出占一行。

数据范围
1≤n≤100
输入样例:
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

老师说找工作前要多攒一些博客
这是我写的第一篇博客
今天正好听课
这是课上的代码
希望不久的将来我可以重做一遍成功AC

  • [1 ] 当做是代办事项吧_(:з」∠)_

法一:BFS//不知道为什么格式错了,我已经没有力气在肝了

#include 
#include 
#include 
#include 
#include 
using namespace std;
int n;

typedef struct Node{
    int num;    //当前的最后一位的大小
    bitset<105> bt; //记录当前路径
    int len;    //当前长度
}node;
queue<node> que;
node result;    //存结果

void bfs(node a) {
    while(!que.empty())     que.pop();
    que.push(a);
    while(!que.empty()) {
        node begins = que.front();
        que.pop();
        if(begins.num == n) {
            result = begins;
            return;
        }
        if(begins.len > result.len || begins.len > 10)
            continue;
        //越快地逼近目标值,从大取到小
        for(int j=begins.num; j!=0; j--) {
            //这个值在序列中,在前面选择的len-1个数里面
            int num = begins.num + j;
            //构造出一个值,num》n没有意义
            //因为维护的是一个单调递增的序列,高造出来的值被取了就没有意义
            if(num <= n && begins.len+1 < result.len && begins.bt[num] == 0) {
                node ends = begins;
                ends.num = num;
                ends.bt[num] = 1;
                ends.len++;
                if(ends.num == n) {
                   result = ends;
                   return ;
                }
                que.push(ends);
            }else if(num < begins.num)  //4+3=7<8   4+2=6<8
                break;
        }
    }
}


int main() {
    while(~scanf("%d", &n) && n) {
        node begins;
        begins.num = 1;
        begins.bt[1] = 1;
        begins.len = 1;
        result.len = 11;
        result.num = 1;
        result.bt = 0;
        bfs(begins);
        int k=0;
        for(int i=1; i<=n; ++i) {
            if(result.bt[i] != 0)
                printf("%d ", i);
        }
        puts("");
    }
    return 0;
}


法二:DFS+迭代加深(优化)//这个就成功AC了

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
//AcWing 170 加成序列
//假设dfs的状态为dfs(int now, int step, int last)

const int mx = 105;
int arr[mx];//搜索数组
bool vis[mx];//标记数组,代表这个值是否走过
int n;

int dfs(int now, int step, int last) {
    if(arr[now] == n)   //最后一个的值等于n
        return now; //返回长度
    if(now > step)  //当前长度大于我们迭代限制的深度
        return 0;   //代表在当前深度是没有答案的
    for(int i=now; i!=0; --i) {
        //优化了, 本来是i!=0, O(n*n)
        //因为前面有一个剪枝,任何的下一个数都由当前的最大值来构成
        for(int j=i; j!=0; --j) {
            //从大到小枚举,搜索顺序优化
            if(!vis[arr[i] + arr[j]] && arr[i]+arr[j] >= last && arr[i]+arr[j]<=n) {
                vis[arr[i]+arr[j]] = 1;
                arr[now+1] = arr[i] + arr[j];   //记录答案
                int flag = dfs(now+1, step, arr[i]+arr[j]);
                //往下搜索
                if(flag)
                    return flag;//在当前的迭代深度找到答案,肯定是最优的
                vis[arr[i]+arr[j]] = 0;
                arr[now+1] = 0;
            } else if(arr[i] + arr[j] < last)
                break;
        }
    }
    return 0;
}


int main() {
    while(~scanf("%d", &n) && n) {
        if(n == 1)
            puts("1");
        else {
            for(int i=2; i<=10; ++i) {//设置迭代的深度
                memset(arr, 0, sizeof(arr));//清空答案数组
                memset(vis, 0, sizeof(vis));//清空标记数组
                arr[1] = 1;
                arr[2] = 2;
                int re = dfs(2, i, arr[2]);//i为迭代深度
                if(re != 0) {
                    for(int i=1; i<=re; ++i)
                        printf("%d ", arr[i]);
                    puts("");
                    break;
                }
            }
        }
    }
    return 0;
}


QAQ菜鸡还要继续加油啊,I am so vegetable. orz

你可能感兴趣的:(搜索)