装载问题 题目描述
解题代码 递归回溯 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 vector<vector<int >> optimalLoading (vector<int >& goods, int c1, int c2) { int n = goods.size (); int maxSum = 0 ; vector<bool > curSelection (n, false ) ; vector<bool > optimSelection; function<void (int , int )> dfs = [&](int sum, int idx) { if (idx == n) { if (sum > maxSum) { maxSum = sum; optimSelection = curSelection; } return ; } if (sum + goods[idx] <= c1) { curSelection[idx] = true ; dfs (sum + goods[idx], idx + 1 ); curSelection[idx] = false ; } dfs (sum, idx + 1 ); }; dfs (0 , 0 ); int sum2 = 0 ; for (int i = 0 ; i < n; ++i) { if (!optimSelection[i]) { sum2 += goods[i]; } } if (sum2 > c2) return {}; vector<vector<int >> res (2 ); for (int i = 0 ; i < n; ++i) { if (optimSelection[i]) { res[0 ].emplace_back (goods[i]); } else { res[1 ].emplace_back (goods[i]); } } return res; }
状态压缩 事实上,对于此类涉及选或不选 的回溯算法,还可以将其写成迭代的形式。
由于递归回溯的本质可以看作是对一棵二叉树进行的搜索,每次选或者不选都将产生两个分支,那么所有情况的数量为 2n (n 为被搜索对象的数目,在本例中为货物的总数)。我们考虑用一个整数 mask 将每种情况表示出来,该整数称为掩码 ,关注它的 n 位二进制形式,其中 mask 的第 i 位二进制位就代表对应的货物 goods[i] 有没有被选择,通常用 1 代表被选择,0 代表不被选择。那么不难得知 mask 的范围为 0~2n -1 。
在得到了每一种情况下的掩码后,就需要对其进行解码 了,可以遍历 0~n-1 的所有整数 i,并将其右移 i 位,将 goods[i] 的对应的二进制位移到了最低位,此时再将和 1 进行按位与 运算就能得知此情况下货物 i 是否被选择。
两种算法都有 2n 中搜索状态,每种状态下需要 O(n) 时间来进行最优解的更新,因此两种算法的渐进时间复杂度都为 O(n * 2n ).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 vector<vector<int >> optimalLoading (vector<int >& goods, int c1, int c2) { int n = goods.size (); vector<bool > curSelection (n, false ) ; vector<bool > optimSelection; int maxSum = 0 ; for (int mask = 0 ; mask < (1 << n); ++mask) { int sum = 0 ; curSelection.assign (n, false ); for (int i = 0 ; i < n; ++i) { bool isChoosed = (mask >> i) & 1 ; if (!isChoosed) continue ; if (sum + goods[i] <= c1) { sum += goods[i]; curSelection[i] = true ; } } if (sum > maxSum) { maxSum = sum; optimSelection = curSelection; } } int sum2 = 0 ; for (int i = 0 ; i < n; ++i) { if (!optimSelection[i]) { sum2 += goods[i]; } } if (sum2 > c2) return {}; vector<vector<int >> res (2 ); for (int i = 0 ; i < n; ++i) { if (optimSelection[i]) { res[0 ].emplace_back (goods[i]); } else { res[1 ].emplace_back (goods[i]); } } return res; }
批处理作业调度 题目描述
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 int batchJobScheduling (vector<vector<int >>& jobs) { int n = jobs.size (); int res = INT32_MAX, curSum = 0 ; int f1 = 0 ; vector<int > f2 (n + 1 , 0 ) ; vector<int > optimSche; vector<int > curSche; for (int i = 0 ; i < n; ++i) { curSche.emplace_back (i); } function<void (int )> dfs = [&](int idx) { if (idx == n) { optimSche = curSche; res = curSum; return ; } for (int j = idx; j < n; ++j) { f1 += jobs[curSche[j]][0 ]; f2[idx + 1 ] = ((f2[idx] > f1) ? f2[idx] : f1) + jobs[curSche[j]][1 ]; curSum += f2[idx + 1 ]; if (curSum < res) { swap (curSche[idx], curSche[j]); dfs (idx + 1 ); swap (curSche[idx], curSche[j]); } f1 -= jobs[curSche[j]][0 ]; curSum -= f2[idx + 1 ]; } }; dfs (0 ); for (int i = 0 ; i < n; ++i) { cout << optimSche[i]; if (i < n - 1 ) cout << "->" ; } return res; }
符号三角形问题 题目描述
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 int signedTriangle (int n) { int num = n * (n + 1 ) / 2 ; if (num % 2 == 1 ) return 0 ; vector<bool > triangles (num, false ) ; int res = 0 ; vector<vector<bool >> fullShape; function<void (int )> dfs = [&](int idx) { if (idx == n) { int pCnt = num / 2 , sCnt = num / 2 ; vector<bool > newShape; queue<bool > q, nq; for (int i = 0 ; i < n; ++i) { q.emplace (triangles[i]); newShape.emplace_back (triangles[i]); --(triangles[i] ? sCnt : pCnt); } while (q.size () > 1 ) { while (q.size () > 1 ) { bool ft = q.front (); q.pop (); bool nt = ft ^ q.front (); nq.emplace (nt); --(nt ? sCnt : pCnt); if (sCnt * pCnt < 0 ) return ; newShape.emplace_back (nt); } q = move (nq); } ++res; fullShape.emplace_back (newShape); return ; } triangles[idx] = true ; dfs (idx + 1 ); triangles[idx] = false ; dfs (idx + 1 ); }; dfs (0 ); for (const auto & shape : fullShape) { for (int col = n; col >= 1 ; --col) { int di = (n - col) * (n + col + 1 ) / 2 ; for (int i = 0 ; i < col; ++i) { cout << shape[i + di]; } cout << endl; } cout << "\n" << endl; } return res; }
N皇后 题目描述
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 vector<vector<string>> solveNQueens (int n) { vector<vector<string>> res; vector<string> chessBoard (n, string(n, '.' )) ; auto check = [&](int r, int c) -> bool { for (int i = 0 ; i < r; ++i) { if (chessBoard[i][c] == 'Q' ) { return false ; } int li = r - i - 1 , lj = c - i - 1 ; if (li >= 0 && lj >= 0 && chessBoard[li][lj] == 'Q' ) { return false ; } int ri = r - i - 1 , rj = c + i + 1 ; if (ri >= 0 && rj < n && chessBoard[ri][rj] == 'Q' ) { return false ; } } return true ; }; function<void (int )> dfs = [&](int idx) { if (idx == n) { res.emplace_back (chessBoard); return ; } for (int j = 0 ; j < n; ++j) { if (!check (idx, j)) continue ; chessBoard[idx][j] = 'Q' ; dfs (idx + 1 ); chessBoard[idx][j] = '.' ; } }; dfs (0 ); return res; }
最大团问题 题目描述
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 struct MGraph { vector<char > vertices; vector<vector<int >> edges; }; vector<vector<char >> largestGroup (MGraph& G) { int n = G.vertices.size (); vector<vector<char >> res; vector<bool > curGroup (n, false ) ; int maxSize = 0 ; function<void (int , int )> dfs = [&](int idx, int curSize) { if (idx == n) { vector<char > group; for (int i = 0 ; i < n; ++i) { if (curGroup[i]) { group.emplace_back (G.vertices[i]); } } if (curSize > maxSize) { res.clear (); maxSize = curSize; } res.emplace_back (group); return ; } bool flag = true ; for (int j = 0 ; j < idx; ++j) { if (curGroup[j] && G.edges[idx][j] == INT32_MAX) { flag = false ; break ; } } if (flag) { curGroup[idx] = true ; dfs (idx + 1 , curSize + 1 ); curGroup[idx] = false ; } if (curSize + n - idx > maxSize) { dfs (idx + 1 , curSize); } }; dfs (0 , 0 ); return res; }
图的m着色问题 题目描述
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 struct MGraph { vector<char > vertices; vector<vector<int >> edges; }; vector<vector<int >> mColoring (MGraph& G, int m) { int n = G.vertices.size (); vector<vector<int >> res; vector<int > coloring (n, -1 ) ; auto check = [&](int idx) -> bool { for (int j = 0 ; j < n; ++j) { if (G.edges[idx][j] != INT32_MAX && coloring[idx] == coloring[j]) { return false ; } } return true ; }; function<void (int )> dfs = [&](int idx) { if (idx == n) { res.emplace_back (coloring); return ; } for (int j = 0 ; j < m; ++j) { coloring[idx] = j; if (check (idx)) { dfs (idx + 1 ); } coloring[idx] = -1 ; } }; dfs (0 ); return res; }
圆排列问题 题目描述
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 double circlePermutation (vector<double >& radius) { int n = radius.size (); double res = INT32_MAX; vector<double > optimalPerm; vector<double > curX (n) ; auto calCenter = [&](int idx) -> double { double xMax = 0.0 ; for (int j = 0 ; j < idx; ++j) { double x = curX[j] + 2.0 * sqrt (radius[idx] * radius[j]); xMax = max (xMax, x); } return xMax; }; auto calLen = [&]() -> double { double low = 0.0 , high = 0.0 ; for (int i = 0 ; i < n; ++i) { low = min (low, curX[i] - radius[i]); high = max (low, curX[i] + radius[i]); } return high - low; }; function<void (int )> dfs = [&](int idx) { if (idx == n) { double len = calLen (); if (len < res) { res = len; optimalPerm = radius; } } for (int j = idx; j < n; ++j) { swap (radius[idx], radius[j]); double centerX = calCenter (idx); if (centerX + radius[idx] + radius[0 ] < res) { curX[idx] = centerX; dfs (idx + 1 ); } swap (radius[idx], radius[j]); } }; dfs (0 ); for (int i = 0 ; i < n; ++i) { cout << optimalPerm[i] << " " ; } return res; }