N个数任意组合相加得不到的数中的最小值

题目:小易邀请你玩一个数字游戏,小易给你一系列的整数。你们俩使用这些整数玩游戏。每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字。 例如: 如果{2,1,2,7}是你有的一系列数,小易说的数字是11.你可以得到方案2+2+7 = 11.如果顽皮的小易想坑你,他说的数字是6,那么你没有办法拼凑出和为6 现在小易给你n个数,让你找出无法从n个数中选取部分求和的数字中的最小数(从1开始)。

输入描述:
输入第一行为数字个数n (n ≤ 20)
第二行为n个数xi (1 ≤ xi ≤ 100000)

输出描述:输出最小不能由n个数选取求和组成的数

示例
输入:
3
5 1 2

输出:
4

题目分析
假如{A1…An}的各种组合的和完全覆盖范围为1~ Kn,比如A1到A3是{1,2,3},那么1~ Kn属于(1,6),(也就是说1~Kn里面的任意一个值都对应着某些组合的和),那么覆盖范围最右端的Kn是A1…An的和。假如说A(n+1)代表第n+1个数值,如果A(n+1)与{A1…An}中任意一个组合再次组合,其和覆盖范围必定是 [A(n+1)+1 , A(n+1)+Kn]。
目前可以知道{A1…A(n)}所有组合的覆盖范围是[1~ Kn] 假设1 ~ Kn是连续的,并上A(n+1)后,覆盖范围是 [A(n+1)+1, A(n+1)+Kn],那么这个覆盖范围是否连续,只需要知道Kn+1>=A(n+1)?,如果等于说明刚好完全覆盖。如果大于说明出现重复覆盖,也就是说不止有一个组合的和为值某个值T,T属于{A(n+1)~Kn}。如果Kn+1<A(n+1),说明中间出现了断层,那么这个断层中最小的值就是最终所求的 得不到的最小值
比如{1,2,3,8},前三个1~A[n]={1,2,3},取值范围1 ~Kn是[1,6],对于第四个,A[n+1]=8,有A[n+1]>Kn+1 ,出现了断层,那么所求的最小不可得到的值就是Kn+1,也就是7
按照以上的思路只需要从n=1的情况开始考虑,一直向后检测就可以了

算法实现

#include<stdio.h>
#include<stdlib.h>
int cmp(const void *a, const void *b){
    
    
    return *(int *)a - *(int *)b;
}
int main(){
    
    
    int n, i, maxSum = 0;
    scanf("%d", &n);
    int x[n];
    for(i = 0; i < n; i++){
    
    
        scanf("%d", &x[i]);
    }
    
    qsort(x, n, sizeof(x[0]), cmp);
    
    for(i = 0; i < n; i++){
    
    
        if(x[i] > maxSum + 1) break;
        maxSum += x[i];
    }
    
    printf("%d", maxSum + 1);
    return 0;
}

qsort 函数原型:

void qsort(void * base , size_t num, size_t width, int( * compare)(const void*,const void*))

各参数:

  1. 待排序数组首地址
  2. 数组中待排序元素数量
  3. 各元素的占用空间大小
  4. 指向函数的指针,用于确定排序的顺序,传入的是地址(分别传入 x[n]和x[n+1])

compare 函数原型:
compare( (void*) & elem1, (void *) & elem2)
compare函数的返回值描述:
“< 0” elem1将被排在elem2之前
“= 0” 位置不变
“> 0” elem1将被排在elem2之后

int cmp(const void *a, const void *b){
return *(int *)a - *(int *)b;
}    //return *(int *)a - *(int *)b;  由小到大排序,反之从大到小

猜你喜欢

转载自blog.csdn.net/weixin_44910502/article/details/112856795