Algorithm 如何计算回溯算法的时间复杂度?

Algorithm 如何计算回溯算法的时间复杂度?,algorithm,complexity-theory,time-complexity,backtracking,Algorithm,Complexity Theory,Time Complexity,Backtracking,如何计算这些回溯算法的时间复杂度,它们是否具有相同的时间复杂度?如果不同怎么办?请详细解释并感谢您的帮助 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) {

如何计算这些回溯算法的时间复杂度,它们是否具有相同的时间复杂度?如果不同怎么办?请详细解释并感谢您的帮助

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
                }
            }
        }
1。哈密顿循环:
bool-hamCycleUtil(bool图[V][V],int-path[],int-pos){
/*基本情况:如果所有顶点都包含在哈密顿循环中*/
如果(位置==V){
//如果从最后包含的顶点到
//第一顶点
if(图[path[pos-1]][path[0]]==1)
返回true;
其他的
返回false;
}
//尝试不同的顶点作为哈密顿循环中的下一个候选顶点。
//我们不尝试0,因为我们在hamCycle()中包含了0作为起点
对于(int v=1;v
实际上我有点困惑,对于断字(b),复杂性是O(2n),但是对于哈密顿循环,它是不同的,对于打印同一字符串的不同排列,然后再解决n皇后问题也是如此

简言之:
  • 哈密顿循环:
    O(N!)
    在最坏的情况下
  • 断字和字符串段:
    O(2^N)
  • 问题:
    O(N!)
  • 注意:对于WordBreak,有一个O(N^2)动态编程解决方案


    更多详情:
  • 在哈密顿循环中,在每个递归调用中,在最坏的情况下选择剩余顶点中的一个。在每个递归调用中,分支因子减少1。在这种情况下,递归可以看作是n个嵌套循环,其中每个循环中的迭代次数减少一次。因此,时间复杂度由下式给出:

    T(N)=N*(T(N-1)+O(1))

    T(N)=N*(N-1)*(N-2)…=O(N!)

  • 类似地,在nqueen中,每次分支因子减少1或更多,但不会太多,因此
    O(N!)

  • 对于WordBreak,它更复杂,但我可以给你一个大概的想法。在WordBreak中,字符串的每个字符在最坏的情况下有两个选择,要么是前一个单词的最后一个字母,要么是新词的第一个字母,因此分支因子为2。因此,对于断字和分段字符串
    T(N)=O(2^N)


  • 回溯算法:

    n-queen问题:O(n!)

    图着色问题:O(nm^n)//其中n=顶点数,m=使用的颜色数

    汉密尔顿循环:O(N!)

    断字和字符串段:O(2^N)


    子集和问题:O(nW)

    如果你专注于实际的回溯(或者更确切地说是每一步的分支可能性),你只会看到指数复杂性。然而,如果回溯只能探索这么多可能的状态,那么它只能探索这些。如果您确保您的算法只访问每个可能的状态一次(并且每个状态的时间限制不变),那么,要探索的可能状态的数量现在是时间复杂度的上限——不管您的算法是否使用回溯。请解释并区分分词b部分和a部分的时间复杂度。对不起,第一个答案,我错误判断了分词b的时间复杂度,不应该是子集的复杂度吗用回溯法求和问题?