简体   繁体   中英

Complexity of backtracking algorithm

I tried to solve this problem using backtracking but I am not sure about the complexity of the algorithm (and if the algorithm is correct) and what would be an algorithm with a better complexity.

Given 2 positive integers n and m, we call legal a sequence of integers if:

  • the length of the sequence is n
  • the elements in the sequence are between 1 and m
  • the element in position i of the sequence, 1 < i <= n, is a divisor of the element in position i-1

Count the number of legal sequences. Expected complexity of the algorithm is O(m² + nm)

This is my algorithm in 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));
}

I think the complexity of my algorithm is O(nmS(n)) with S(n) = the number of legal sequences

You are correct that your program runs in the solution space of problem. For this type of problem, your solution is sub-optimal for large input (say n = m = 100 ). That is because the solution space grows exponentially in relation to m and n . Here is a solution that uses memoization to avoid re-computations:

#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));
}

The code above runs in the time complexity you mentioned.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM