Addition Chains UVA - 529

原题链接

考察:迭代加深搜索

思路:

        迭代加深适用于预测的答案较小的情况,它比bfs更省空间.这里的加成序列在n<=10000的情况下,长度最长不超过14.因此可以用迭代加深.

        光是迭代加深还是会T到爆,所以需要一些剪枝:

        1.搜索顺序剪枝:每次优先处理结点少的分支,所以尽可能枚举大的点.所以我们从大到小枚举前面的数字.

        2.排除冗余:        (1)可以发现a[j]+a[i]与a[i]+a[j]完全相同,所以组合式枚举.

                                  (2)如果a+b == c+d 那么下一步到达的结点相同,搜索了a+b就没必要搜索c+d

        3.可行性剪枝(最重要):可以发现如果当前数是s,枚举到第i位.那么最大能扩展到s<<(len-i).如果最大都<n就没必要扩展.

        4.迭代加深每次都从1开始,1~i层重复搜.根据上面最大能扩展的数,我们可以从最大>=n的层数开始搜索.

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <set>
 5 using namespace std;
 6 const int N = 110;
 7 int a[N],n,len,logs[N];
 8 bool dfs(int idx)//枚举到第idx个
 9 {
10     if(a[idx]==n)
11     {
12         for(int i=1;i<=idx;i++)
13           printf("%d%c",a[i],i==idx?'\n':' ');
14         return 1;
15     }
16     if((a[idx]<<(len-idx))<n) return 0;
17     if(idx>=len) return 0;
18     set<int> s;
19     for(int i=idx;i>=1;i--)//组合枚举
20     {
21         int st = upper_bound(a+1,a+idx+1,a[idx]-a[i])-a;
22         for(int j=i;j>=st;j--)
23         {
24             if(a[j]+a[i]<=a[idx]||s.count(a[j]+a[i])||a[j]+a[i]>n) continue;
25             a[idx+1] = a[j]+a[i];
26             if(dfs(idx+1)) return 1;
27             s.insert(a[j]+a[i]);
28         }
29     }
30     return 0;
31 }
32 int main()
33 {
34     logs[1] = 1;
35     for(int i=2;i<=14;i++) logs[i] = logs[i-1]*2;
36     while(scanf("%d",&n)!=EOF&&n)
37     {
38         a[1] = 1;
39         len = lower_bound(logs+1,logs+9,n)-logs;
40         while(1)
41         {
42             if(dfs(1)) break;
43             len++;
44         }
45     }
46     return 0;
47 }

 

posted @ 2021-04-19 13:05  acmloser  阅读(41)  评论(0编辑  收藏  举报