web-dev-qa-db-fra.com

Comment calculer la complexité temporelle de l'algorithme de retour en arrière?

Comment calculer la complexité temporelle de ces algorithmes de retour en arrière et ont-ils la même complexité temporelle? Si différent comment? Veuillez expliquer en détail et merci pour l'aide. 

1. Hamiltonian cycle:

        bool hamCycleUtil(bool graph[V][V], int path[], int pos) {
            /* base case: If all vertices are included in Hamiltonian Cycle */
            if (pos == V) {
                // And if there is an Edge from the last included vertex to the
                // first vertex
                if ( graph[ path[pos-1] ][ path[0] ] == 1 )
                    return true;
                else
                    return false;
            }

            // Try different vertices as a next candidate in Hamiltonian Cycle.
            // We don't try for 0 as we included 0 as starting point in in hamCycle()
            for (int v = 1; v < V; v++) {
                /* Check if this vertex can be added to Hamiltonian Cycle */
                if (isSafe(v, graph, path, pos)) {
                    path[pos] = v;

                    /* recur to construct rest of the path */
                    if (hamCycleUtil (graph, path, pos+1) == true)
                        return true;

                    /* If adding vertex v doesn't lead to a solution, then remove it */
                    path[pos] = -1;
                }
            }

            /* If no vertex can be added to Hamiltonian Cycle constructed so far, then return false */
            return false;
        }

2. Word break:

       a. bool wordBreak(string str) {
            int size = str.size();

            // Base case
            if (size == 0)
                return true;

            // Try all prefixes of lengths from 1 to size
            for (int i=1; i<=size; i++) {
                // The parameter for dictionaryContains is str.substr(0, i)
                // str.substr(0, i) which is prefix (of input string) of
                // length 'i'. We first check whether current prefix is in
                // dictionary. Then we recursively check for remaining string
                // str.substr(i, size-i) which is suffix of length size-i
                if (dictionaryContains( str.substr(0, i) ) && wordBreak( str.substr(i, size-i) ))
                    return true;
            }

            // If we have tried all prefixes and none of them worked
            return false;
        }
    b. String SegmentString(String input, Set<String> dict) {
           if (dict.contains(input)) return input;
           int len = input.length();
           for (int i = 1; i < len; i++) {
               String prefix = input.substring(0, i);
               if (dict.contains(prefix)) {
                   String suffix = input.substring(i, len);
                   String segSuffix = SegmentString(suffix, dict);
                   if (segSuffix != null) {
                       return prefix + " " + segSuffix;
                   }
               }
           }
           return null;
      }


3. N Queens:

        bool solveNQUtil(int board[N][N], int col) {
            /* base case: If all queens are placed then return true */
            if (col >= N)
                return true;

            /* Consider this column and try placing this queen in all rows one by one */
            for (int i = 0; i < N; i++) {
                /* Check if queen can be placed on board[i][col] */
                if ( isSafe(board, i, col) ) {
                    /* Place this queen in board[i][col] */
                    board[i][col] = 1;

                    /* recur to place rest of the queens */
                    if ( solveNQUtil(board, col + 1) == true )
                        return true;

                    /* If placing queen in board[i][col] doesn't lead to a solution then remove queen from board[i][col] */
                    board[i][col] = 0; // BACKTRACK
                }
            }
        }

Je suis un peu confus, quant à Word Break (b), la complexité est O (2n) mais pour Hamilton, son cycle est différent et il en est de même pour l’impression de permutations différentes de la même chaîne, puis pour la résolution du problème n reens. 

16
da3m0n

En bref:

  1. Cycle hamiltonien: O(N!) dans le pire des cas
  2. WordBreak et StringSegment: O(2^N)
  3. NQueens: O(N!)

Remarque: pour WordBreak, il existe une solution de programmation dynamique O (N ^ 2).


Plus de détails:

  1. Dans le cycle hamiltonien, dans chaque appel récursif, l'un des sommets restants est sélectionné dans le pire des cas. Dans chaque appel récursif, le facteur de branche diminue de 1. Dans ce cas, la récursivité peut être assimilée à n boucles imbriquées où, dans chaque boucle, le nombre d'itérations diminue de un. D'où la complexité temporelle est donnée par:

    T(N) = N*(T(N-1) + O(1))
    T(N) = N*(N-1)*(N-2).. = O(N!)

  2. De même dans NQueens, chaque fois que le facteur de branchement diminue de 1 ou plus, mais pas beaucoup, d’où la limite supérieure de O(N!)

  3. Pour WordBreak, c'est plus compliqué, mais je peux vous donner une idée approximative. Dans WordBreak, chaque caractère de la chaîne a deux choix dans le pire des cas, soit être la dernière lettre du mot précédent, soit la première lettre d'un nouveau mot, d'où le facteur de ramification est 2. Par conséquent, pour WordBreak et SegmentString T(N) = O(2^N)

19
Vikram Bhat

Algo backtracking:

problème n-reine: O (n!)

problème de coloration des graphes: O (nm ^ n) // où n = non. du sommet, m = non. de couleur utilisée

cycle d'hamilton: O (N!)

WordBreak et StringSegment: O (2 ^ N)

problème de somme de sous-ensembles: O(nW)

2
Shyam Bhimani