原本用來解題的,結果題目由於特殊性有更好的解法,但寫了半天作個單獨備份,這是該類問題較通用的解決方式。 主要框架是遞歸爆破,經過dp收集數據,使用回溯減小計算路徑。 question: 輸入一串數字,將其按照任意順序排爲一列,求可以使全部 位置相鄰的數的差的絕對值有k個不一樣值的排列 sample : 集合 1 2 3 4 6, 該排列知足 k = 2 解答: #include <iostream> #include <fstream> #include <cstdlib> #include <stack> #include <string> #include <set> #include <cstring> #include <cmath> #include <vector> using namespace std; #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) > (b) ? (b) : (a)) #define abs(a) ((a) > 0 ? (a) : (0 - (a))) #define CLR(vec) memset(vec, 0, sizeof(vec)) #ifdef DEBUG ifstream in; ofstream out; #define CIN in #define COUT out #else #define CIN cin #define COUT cout #endif #define MAXN 100010 int table[MAXN]; /*store input nums*/ int diff[MAXN]; /*record difference between nums*/ int cnt; /*tot distinct differnece*/ int n, k; int success; #define swap(a, b) do{\ int stmp;\ stmp = a;\ a = b;\ b = stmp;\ }while(0) void solve(int *a, int left){ int record = -1; /*record which diff changed in this depth*/ int tmp; #ifdef DEBUG for(int i = 0; i < n; i++) COUT << table[i] << " "; COUT << "-->" << cnt << "\n"; #endif if(success) return; if(0 == left){ /*enum end*/ if(cnt == k){ success = 1; for(int i = 0; i < n - 1; i++){ COUT << table[i] << " "; } COUT << table[n - 1] << "\n"; } return; } if(left + cnt < k) /*backtracking*/ return; for(int i = 0; i < left; i++){ swap(a[0], a[i]); if(left != n){ /*dp here and save status*/ tmp = abs(a[0] - a[-1]); if(0 == diff[tmp]){ diff[tmp] = 1; cnt++; record = tmp; } } solve(a + 1, left -1); if(record > 0){ /*recover status*/ diff[record] = 0; cnt--; record = -1; } swap(a[0], a[i]); } } int main(void){ ios_base::sync_with_stdio(0); #ifdef DEBUG CIN.open("./in", ios::in); COUT.open("./out", ios::out); #endif CIN >> n >> k; for(int i = 0; i < n; i++) CIN >> table[i]; cnt = 0; solve(table, n); /*solve problem*/ return 0; }