最少的元素个数使和为 target

思路

这是 0/1 背包的变种。

设 dp[j] 表示凑出和 j 所需的最少元素个数。

  • 初始化 dp[0] = 0,其他为无穷大。

  • 对每个数 x,从后往前更新:

    dp[j] = min(dp[j], dp[j - x] + 1)

但 target 可能为负,且数组元素可能为负,因此不能直接用下标表示负数。

若 target 绝对值不大,可以加偏移量 OFFSET。

若 target 绝对值过大,则伪多项式算法不可行,应说明使用 meet-in-the-middle 或搜索剪枝。

这里给出偏移量版本。

代码

c

复制代码
#include <stdio.h>
#include <string.h>
#include <limits.h>

#define MAXN 1005
#define MAXT 200005
#define INF 0x3f3f3f3f

int min(int a, int b) {
    return a < b ? a : b;
}

int main() {
    int n, target;
    int nums[MAXN];
    int dp[MAXT];
    int offset = 100000;

    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%d", &nums[i]);
    scanf("%d", &target);

    int size = 200005;
    for (int i = 0; i < size; i++) dp[i] = INF;
    dp[offset] = 0;

    for (int i = 0; i < n; i++) {
        int x = nums[i];
        if (x >= 0) {
            for (int j = size - 1; j >= x; j--) {
                if (dp[j - x] != INF)
                    dp[j] = min(dp[j], dp[j - x] + 1);
            }
        } else {
            for (int j = 0; j < size + x; j++) {
                if (dp[j - x] != INF)
                    dp[j] = min(dp[j], dp[j - x] + 1);
            }
        }
    }

    int idx = target + offset;
    if (idx < 0 || idx >= size || dp[idx] == INF)
        printf("-1\n");
    else
        printf("%d\n", dp[idx]);

    return 0;
}
相关推荐
Rabitebla15 小时前
【Linux 底层原理】进程(十):进程等待详解---从僵尸进程到 wait、waitpid 与 status
linux·c++·笔记·学习·visual studio
西西弗Sisyphus17 小时前
C++ 超时互斥锁(Timed Mutex):std::timed_mutex 与 std::unique_lock
c++
其实防守也摸鱼19 小时前
个人学习 Pwn 思路:从基础到漏洞利用的进阶路径
大数据·前端·人工智能·chrome·算法·安全·网络安全
今天要早睡_19 小时前
C++01_入门基础复习
开发语言·c++
Nuanyt20 小时前
LeetCode Hot 100 链表专题(五)· 2 题(Java)
java·算法·leetcode·链表
Fuyo_11191 天前
C++ 运行时多态与虚函数机制全面剖析【面试重点】
开发语言·c++·面试
w_zero_one1 天前
递归算法(一)
java·开发语言·算法
Chen_harmony1 天前
七、STL与string类
开发语言·c++
xxxiugou1231 天前
C++命名空间与引用全解析
开发语言·c++