我尝试使用回溯来解决这个问题,但我不确定算法的复杂性(如果算法是正确的)以及具有更好复杂性的算法。
给定2个正整数n和m,如果符合以下条件,我们称合法为整数序列:
计算合法序列的数量。算法的预期复杂度为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)=合法序列的数量
答案 0 :(得分:0)
您的程序在问题的解决方案空间中运行是正确的。对于此类问题,您的解决方案对于大输入(例如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));
}
上面的代码以你提到的时间复杂度运行。