【复旦大学历年机试题】2021-03(动态规划)

在这里插入图片描述
题目:给定一个非负整数序列 x1, x2, …, xn,可以给每一个整数取负数或者取原值,求有多少种取法使得这些整数的和等于期望值 E。请写出程序,并解释解题思路。

输入样例
非负整数序列为 1 1 1 1 1 3 (期望值 E 为 3)
输出样例
5
输出描述:
5 种取法分别为:
-1+1+1+1+1 = 3
1-1+1+1+1 = 3
1+1-1+1+1 = 3
1+1+1-1+1 = 3
1+1+1+1-1 = 3

题解:本题是动态规划目标和问题,假设加法的总和为x,那么减法对应的总和就是sum - x。所以我们要求的是 x - (sum - x) = target,即x = (target + sum) / 2,此时问题就转化为,用nums装满容量为x的背包,有几种方法。这里的x,就是bagSize,也就是我们后面要求的背包容量。
(1)确定dp数组及其下标含义:dp[j],表示:填满j(包括j)这么大容积的包,有dp[j]种方法;
(2)确定递推公式:dp[j] += dp[j - nums[i]];
(3)确定初始化方式:dp[0] = 1;
(4)遍历顺序:遍历物品放在外循环,遍历背包在内循环,且内循环倒序(为了保证物品只使用一次);
(5)举例推导dp数组

代码(C++)

#include <bits/stdc++.h>
using namespace std;

int main(){
    vector<int> nums;
    int data;  // 输入数据

    // 输入
    while(cin >> data){
        nums.push_back(data);
        if(getchar() == '\n')  break;
    }
    int target = nums[nums.size() - 1];
    nums.pop_back();
    int size = nums.size();
    int sum = 0;
    for(int i = 0;i < size;i++){  // 求总和
        sum += nums[i];
    }
    int bagsize = (sum + target) / 2;
    if((sum + target) % 2) return 0;  //加法和不为整数,一定没有方案
    if(sum < abs(target)) return 0;  //运算结果一定不得target
    vector<int> dp(bagsize+1,0);  //初始化数组,使表达式结果为target的方法数目

    dp[0] = 1;  //初始化
    for(int i = 0;i < size;i++){  //遍历
        for(int j = bagsize;j >= nums[i];j--){
            dp[j] = dp[j] + dp[j-nums[i]];  //递推公式
        }
    }

    // 输出
    printf("%d\n", dp[bagsize]);

    return 0;
}

写在后面

这个专栏主要是我在刷题的过程中总结的一些笔记,因为我学的也很一般,如果有错误和不足之处,还望大家在评论区指出。希望能给大家的学习带来一点帮助,共同进步!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值