求n个数排为一列后相邻数的差的绝对值不同的个数为K的序列

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


你可能感兴趣的:(求n个数排为一列后相邻数的差的绝对值不同的个数为K的序列)