求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;
}


转载于:https://my.oschina.net/u/572632/blog/356237

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这道题目是在n个数中,绝对值最小的两个值。 解题思路: 1. 首先将这n个数从小到大排序。 2. 然后计相邻两个之间的值,找到值最小的两个。 3. 最后计两个值,就是所的答案。 代码实现: 假设这n个数存储在组a中,代码如下: ```python n = len(a) a.sort() # 排序 min_diff = float('inf') # 初始化值为正无穷大 for i in range(n-1): diff = abs(a[i] - a[i+1]) # 计相邻两个之间的值 if diff < min_diff: min_diff = diff x, y = a[i], a[i+1] # 记录值最小的两个 ans = abs(x - y) # 计两个值 print(ans) ``` 注意事项: 1. 如果有多组值相同的对,只需要输出其中任意一组即可。 2. 如果n小于等于1,那么值为。 3. 在计值时,要注意绝对值的使用。 ### 回答2: 假设给定的n个数为a1,a2,a3,...,an,那么我们需要找到其中绝对值最小的2个数,假设它们为x和y,不妨设x<y。 由于我们要的是x和y的值,那么我们需要先找到它们的值。我们可以先将这n个数从小到大排序,然后依次比较相邻两个,找出值最小的一对。如果存在两对值相等的对,那么我们需要选择其中值较小的那对。 有了x和y的值之后,它们之间的值就可以直接计出来了。即y-x。 设最小的值为d,那么我们需要对每一对相邻进行比较,找出绝对值最小的一对。假设这对为ai和ai+1,则有: |ai - ai+1| <= d 为了让这个值最小,我们可以将x和y设为这两个中的较小值和较大值,这样它们的值就是d,同时也满足原问题的条件。 因此,我们可以使用排序的方法将n个数从小到大排列,然后依次比较相邻两个,找到相最小的一对即可。时间复杂度为O(nlogn)。 ### 回答3: 假设有一个数组a,其中共有n个数字,我们的任务是从中找出绝对值最小的两个字,并计它们的值b。 首先我们需要明确一点,绝对值最小的两个字必然是相邻的,因为只有相邻字之间才可能有相同的值。因此我们可以将组a进行排序,然后查找相邻值的最小值,最终得到的这个值即为我们要的b。 具体实现过程如下: 1. 对组a进行排序,使得字按照从小到大的顺序排列。 2. 定义一个变量min_diff,用于保存当前找到的绝对值最小的两个字之间的值,初值设为a[1]-a[0]。 3. 对于i从1到n-1,依次计相邻字之间的值diff,如果diff比min_diff小,则更新min_diff为diff。 4. 循环结束后,min_diff即为所绝对值最小的两个值b。 整个过程的时间复杂度为O(nlogn)+O(n),其中O(nlogn)是排序的时间复杂度。如果使用桶排序,则时间复杂度可以优化为O(n)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值