原本用来解题的,结果题目由于特殊性有更好的解法,但写了半天作个单独备份,这是该类问题较通用的解决方式。 主要框架是递归爆破,经过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; }