第1部分 基礎算法(提高篇)--第3章 深搜的剪枝技巧1443:【例題4】Addition Chains

1443:【例題4】Addition Chains

時間限制: 1000 ms 內存限制: 65536 KB
提交數: 968 通過數: 478
【題目描述】
已知一個數列a0,a1……am,其中a0=1,am=n; a0<a1<a2<……<am−1<am。對於每個k(1≤k≤m)滿足ak=ai+aj(0≤i,j≤k−1),這裏i與j可以相等。

現給定n的值,要求m的最小值(並不要求輸出)及這個數列的值(可能存在多個數列,只輸出任意一個滿足條件的就可以)。

【輸入】
多組數據,每行給定一個正整數n。輸入以0結束。

【輸出】
對於每組數據,輸出滿足條件的長度最小的數列。

【輸入樣例】
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


思路:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define INF 0X3F3F3F3F
#define N 2019
using namespace std;

int n,minn,ans[N],a[N];
//n是序列的最大值
//minn是拆數字最小層數 
//ans存答案
//a是一個過程中起記錄作用的數組 

void dfs(int x)  //遞歸第x層 
{
    if(x-1 > minn) return ;  //超過最小層數,剪枝 
    if(a[x-1] > n) return;   //上一層的數字大於最大值n,剪枝 
    if(a[x-1] == n)  //上一層的數字=n,有希望構成一個完整解答 
    {
        if((x-1) >= minn) return; //層數超了 
           minn = x-1;   //記下暫定答案 
        for(int i=1;i < x;i++) ans[i] = a[i];
    }
    else
    {
        for(int j = x-1;j >= 1;j--)  
        //ak=ai+aj,倒着枚舉,看看能否繼續擴展下一層 
        {
            if(a[x-1]+a[j] <= n)
            {
                a[x] = a[x-1]+a[j];  //可以繼續擴展 
                dfs(x+1); 
                a[x] = 0;  //回溯 
            }
        }
    }
}

int main()
{
    while(scanf("%d",&n) != EOF) //輸入非空 
    {
        if(n == 0) break;
        else
        {
            a[1] = 1;  //初始化第一層爲1 
            minn = INF;  //拆數字的最小層數 
            dfs(2);  //從第二層開始遞歸 
            for(int i = 1;i <= minn;i++) printf("%d ",ans[i]); //確定層數,輸出答案 
            printf("\n");
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章