搜索_DFS_迭代加深_POJ2248_Addition Chains

版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84196263

点此打开题目页面

思路分析:

    可通过枚举序列的前i - 1个数两两之和确定第i个数的值, 考虑到100 = 50 + 50, 50 = 25 + 25, 25 = 13 + 12, 13 = 7 + 6, 7 = 4 + 3. 4 = 2 + 2, 3 = 1 + 2, 因此当n <= 100时, 最小的m值不会超过12, 因此考虑使用迭代加深DFS并使用如下剪枝策略

    (1)确定第i个数时避免考察某个和多次

    (2)如果已经计算出一个当前的最优解s, 且当前结点比s少一个数, 设当前结点最后一个数为k, 且k + k >= n, 那么立即回溯

    (3)从较大的和开始枚举

    基于上述剪枝策略给出如下AC代码:

//POJ2248_Addition Chains
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int NIL = 0x3f3f3f3f;
int n, deep, ans; vector<int> path, ansv;
void dfs(){
	if(path.size() >= ans || ans != NIL && (path.size() >= ans - 1 && path.back() * 2 <= n)) return;
	if(path.size() == deep){
		if(path.back() == n) ans = path.size(), ansv = path; return;
	}
	if(path.back() == n){
		ans = path.size(), ansv = path; return;
	}
	bool used[101];
	memset(used, false, sizeof(used));
	for(int i = path.size() - 1; i >= 0; --i)
		if(path[i] * 2 <= path.back()) return;
		else
			for(int j = i; j >= 0; --j)
				if(path[i] + path[j] > n || used[path[i] + path[j]]) continue; 
				else used[path[i] + path[j]] = true, path.push_back(path[i] + path[j])
					 , dfs(), path.pop_back();
}
int main(){
	while(scanf("%d", &n), n){
		ans = NIL, deep = 0;
		while(ans == NIL) ++deep, ansv.clear(), path.clear(), path.push_back(1), dfs();
		for(int i = 0; i < ansv.size(); ++i) cout << ansv[i] << " "; cout << endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/solider98/article/details/84196263