回溯算法的复杂度
Posted
技术标签:
【中文标题】回溯算法的复杂度【英文标题】:Complexity of backtracking algorithm 【发布时间】:2017-06-14 14:14:20 【问题描述】:我尝试使用回溯来解决这个问题,但我不确定算法的复杂性(以及算法是否正确)以及更复杂的算法。
给定 2 个正整数 n 和 m,如果满足以下条件,我们称合法整数序列:
序列长度为n 序列中的元素在 1 到 m 之间 序列中位置 i 的元素 1计算合法序列的数量。算法的预期复杂度为 O(m² + nm)
这是我在 c 中的算法:
// n length of the sequence
// m maximum valid number
// l number of remaining positions in the sequence
// p previous number in the sequence
int legal(int n, int m, int l, int p)
if (l == 0)
return 1;
int q=0;
for (int i=1; i <= m;i++)
if (p%i == 0 || l == n)
q += legal(n,m,l-1,i);
return q;
int main()
int n, m;
scanf("%d", &n);
scanf("%d", &m);
printf("%d\n", legal(n,m,n,0));
我认为我的算法的复杂度是 O(nmS(n)) 其中 S(n) = 合法序列的数量
【问题讨论】:
算法的代码或伪代码应该包含合理的名称或关于什么字母意味着什么的字典。评论也很有用。您发表的内容是对所有读者和可能的回答者的完全不礼貌。请添加解释。 ***.com/questions/20049829/… 【参考方案1】:您的程序在问题的解决方案空间中运行是正确的。对于此类问题,您的解决方案对于大输入(比如n = m = 100
)来说是次优的。这是因为解决方案空间相对于m
和n
呈指数增长。这是一个使用memoization 来避免重新计算的解决方案:
#include <cstdio>
#define LIMIT 101
#define DIRTY -1
long long cache[LIMIT][LIMIT];
void clear_cache()
for (int i = 0; i < LIMIT; i++)
for (int j = 0; j < LIMIT; j++)
// marked all entries in cache as dirty
cache[i][j] = DIRTY;
long long legal_seqs(int curr_len, int prev_num, int seq_len, int max_num)
// base case
if (curr_len == seq_len) return 1;
// if we haven't seen this sub-problem, compute it!
// this is called memoization
if (cache[curr_len][prev_num] == DIRTY)
long long ways = 0;
// get all multiples of prev_num
for (int next_num = 1; next_num <= max_num; next_num++)
if (prev_num % next_num == 0)
ways += legal_seqs(curr_len + 1, next_num, seq_len, max_num);
cache[curr_len][prev_num] = ways;
return cache[curr_len][prev_num];
int main()
int n, m;
scanf("%d%d", &n, &m);
clear_cache();
printf("%lld\n", legal_seqs(0, 0, n, m));
上面的代码以你提到的时间复杂度运行。
【讨论】:
非常感谢...您能解释一下您的算法的时间复杂度分析吗?我认为如果我们用输入 n 和 m 替换常量 LIMIT,子程序 clear_cache 运行在 O(nm) 并且 legal_seqs 也运行在 O(nm) 中,而不是算法运行在 O( n*m)以上是关于回溯算法的复杂度的主要内容,如果未能解决你的问题,请参考以下文章