void backtrack(vector<int>& nums, vector<bool>& used, vector<int>& path, vector<vector<int>>& res) {
if (path.size() == nums.size()) {
res.push_back(path);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (used[i]) continue;
used[i] = true;
path.push_back(nums[i]);
backtrack(nums, used, path, res);
path.pop_back();
used[i] = false;
}
}
#include <bits/stdc++.h>
using namespace std;
void permute(const vector<int>& nums, vector<bool>& used, vector<int>& path, vector<vector<int>>& res) {
if (path.size() == nums.size()) {
res.push_back(path);
return;
}
for (int i = 0; i < (int)nums.size(); i++) {
if (used[i]) continue;
used[i] = true;
path.push_back(nums[i]);
permute(nums, used, path, res);
path.pop_back();
used[i] = false;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
if (!(cin >> n)) return 0;
vector<int> nums(n);
for (int i = 0; i < n; i++) cin >> nums[i];
vector<bool> used(n, false);
vector<int> path;
vector<vector<int>> res;
permute(nums, used, path, res);
for (auto& p : res) {
for (int i = 0; i < (int)p.size(); i++) {
if (i) cout << ' ';
cout << p[i];
}
cout << '\n';
}
return 0;
}
輸入: 3 1 2 3 輸出: 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1
| 指標 | 複雜度 | 說明 |
|---|---|---|
| 時間 | O(n! × n) | n! 個排列,每個複製 O(n) |
| 空間 | O(n) | 遞歸棧 + path + used |
註:輸出本身即需 O(n! × n) 時間,算法已達理論最優。
vector<int> a = nums;
sort(a.begin(), a.end());
do {
// 處理 a
} while (next_permutation(a.begin(), a.end()));
used 數組。排序後,在回溯循環中添加剪枝:
if (i > 0 && nums[i] == nums[i-1] && !used[i-1]) continue;
確保相同數值只在第一次未使用時被選取,避免重複排列。
全排列是回溯算法的入門範本。掌握「路徑、選擇列表、終止條件」三要素,即可推導出組合、子集、N 皇后等所有回溯問題。工程中優先用 next_permutation,面試手寫回溯框架需熟練到「閉眼能寫」。