1. 程式人生 > >搜尋_DFS_迭代加深_POJ2248_Addition Chains

搜尋_DFS_迭代加深_POJ2248_Addition Chains

點此開啟題目頁面

思路分析:

    可通過列舉序列的前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;
}