poj 2248 Addition Chains(迭代加深搜索)

题目

一个与 n n n有关的整数加成序列 &lt; a 0 , a 1 , a 2 , . . . , a m &gt; &lt;a_0,a_1,a_2,...,a_m&gt; <a0,a1,a2,...,am>满足以下四个条件:
1. a 0 = 1 1.a_0=1 1.a0=1
2. a m = n 2.a_m=n 2.am=n
3. a 0 &lt; a 1 &lt; a 2 &lt; . . . &lt; a m − 1 &lt; a m 3.a_0&lt;a_1&lt;a_2&lt;...&lt;a_{m-1}&lt;a_m 3.a0<a1<a2<...<am1<am
4. 4. 4.对于每一个 k ( 1 ≤ k ≤ m ) k(1≤k≤m) k(1km)都存在有两个整数 i i i j j j ( 0 ≤ i , j ≤ k − 1 (0≤i,j≤k-1 (0i,jk1, i i i j j j可以相等 ) ) ),使得 a k = a i + a j a_k=a_i+a_j ak=ai+aj
你的任务是:给定一个整数 n n n,找出符合上述四个条件的长度最小的整数加成序列。如果有多个满足要求的答案,只需要输出任意一个解即可。
举个例子,序列 &lt; 1 , 2 , 3 , 5 &gt; &lt;1,2,3,5&gt; <1,2,3,5> &lt; 1 , 2 , 4 , 5 &gt; &lt;1,2,4,5&gt; <1,2,4,5>均为 n = 5 n=5 n=5时的解。

poj2248

题解

  • 蒟蒻的迭代加深入门题qwq
  • 首先我看到这道题的时候不知道该怎么写, d f s dfs dfs?但是不知道序列中有几个数。 b f s bfs bfs?但是状态该怎么记录。蒟蒻内心是崩溃的awsl
  • 于是我就打了一个玄学暴搜,水过了30分qaq
  • 下面开始 b b bb bb正解
  • 首先搜索一定要有明确的搜索框架,要明确自己要搜什么,不能漫无目的。对于这道题来说我们可以依次搜索序列中的每个位置 k k k,枚举 i , j i,j i,j,使得 x [ k ] = x [ i ] + x [ j ] x[k]=x[i]+x[j] x[k]=x[i]+x[j]
  • 但是这样搜无疑效率很低,我们考虑剪枝:
    1. 优化搜索顺序:为了让序列中的数字尽快接近 n n n,我们可以从大到小来枚举 i , j i,j i,j
    2. 排除等效冗余:对于不同的 i , j i,j i,j x [ i ] + x [ j ] x[i]+x[j] x[i]+x[j]可能是相等的,我们可以在枚举时开一个 b o o l bool bool数组记录重复即可。
  • (敲黑板重点来了 对于本题来说,它的搜索分支非常的大,而最终状态却不会太大(序列长度 ≤ 10 \leq10 10),于是我们可以限制搜索的深度,从1开始,如果大于当前的搜索深度立即退出,如果找到解则肯定是最优解退出即可。
  • 这种限制搜索深度的方法就被称为迭代加深

c o d e code code

#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <list>
#include <map>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std; 
const int maxn = 110; 

template <class T> 
inline void read(T &s) {
   s = 0; 
   T w = 1, ch = getchar(); 
   while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
   while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
   s *= w;  
} 

int n, idt; 
int ans[maxn]; 

bool dfs(int k) {
   if (k > idt) {
   	return ans[idt] == n ? true : false; 
   }
   bool vis[105]; 
   memset(vis, 0, sizeof(vis)); 
   // memset(vis, false, sizeof(vis)); 
   for (int i = k - 1; i >= 1; --i) {
   	for (int j = i; j >= 1; --j) {
   		if (ans[i] + ans[j] > n) continue; 
   		if (vis[ans[i]+ans[j]]) continue; 
   		if (ans[i] + ans[j] <= ans[k-1]) return false; 
   		ans[k] = ans[i] + ans[j]; 
   		vis[ans[k]] = true; 
   		if (dfs(k + 1)) return true; 
   	}
   }
   return false; 
}

int main() {
   ans[1] = 1; 
   ans[2] = 2; 
   while (1) {
   	read(n); 
   	if (!n) break; 
   	if (n == 1) { puts("1"); continue; }
   	for (idt = 1; ; ++idt) {
   		if (dfs(2)) {
   			for (int i = 1; i <= idt; ++i) 
   				printf("%d ", ans[i]); 
   			puts(""); 
   			break; 
   		}
   	}
   }
   return 0; 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值