本来用来解题的,结果题目因为特殊性有更好的解法,但写了半天做个单独备份,这是该类问题较通用的解决方式。
主要框架是递归爆破,通过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;
}
转载于:https://my.oschina.net/u/572632/blog/356237