PTA 子集和问题(回溯法):给定集合S,S中有n个正整数,M是一个正整数。...

问题
给定集合S,S中有n个正整数,M是一个正整数。子集和问题判定是否存在S的一个子集S1,使得S1中各元素之和等于M。请设计回溯法求解子集和问题,如果问题无解,输出“No Solution”,问题有解,则输出满足子集S1中各元素的值。

输入样例

4 31
13 24 11 7

输出样例

13 24 11 7
24 7

详解请看代码注释

源代码

#include<iostream>

using namespace std;

int* arr,*result;                  // arr表示数据数组;result表示解数组,用于存储解向量
int M, n, sum=0, cnt=0;            // M表示目标正整数,n表示集合中的元素个数,cnt表示解的个数
void backTrack
  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 题目描述: 给定n个不同正整数集合w=(w1,w2,…,wn)和一个正数w,要求找出w的子集s,使该子集中所有元素的和为w。 解题思路: 这是一个经典的背包问题,可以使用动态规划来解决。 定义一个二维数组dp[i][j],表示前i个数中是否存在一个子集,使得它们的和为j。则有以下状态转移方程: dp[i][j] = dp[i-1][j] || dp[i-1][j-w[i]] 其中,dp[i-1][j]表示不选第i个数,dp[i-1][j-w[i]]表示选第i个数。 最终,如果dp[n][w]为true,则说明存在一个子集,使得它们的和为w。 代码实现: bool subsetSum(vector<int>& nums, int target) { int n = nums.size(); vector<vector<bool>> dp(n+1, vector<bool>(target+1, false)); for (int i = ; i <= n; i++) { dp[i][] = true; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= target; j++) { if (j < nums[i-1]) { dp[i][j] = dp[i-1][j]; } else { dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i-1]]; } } } return dp[n][target]; } ### 回答2: 这是一个经典的0-1背包问题,可以用DP(动态规划)方法来解决。 具体做法是:定义二维数组dp[i][j]表示前i个数中是否存在一个子集的和为j,如果存在,则dp[i][j]为true,否则为false。对于每个数wi,我们可以选择将其放入子集中或不放入子集中: 1. 如果wi > j,则wi一定不能放入子集中,即dp[i][j] = dp[i-1][j]; 2. 如果wi <= j,则可以选择将其放入子集中,或不放入子集中。如果不放入子集中,则子集中的和为j,即dp[i][j] = dp[i-1][j];如果放入子集中,则子集中的和为j-wi,即dp[i][j] = dp[i-1][j-wi]。因此,综合上述情况,得到DP转移方程为: dp[i][j] = dp[i-1][j] || dp[i-1][j-wi] (当wi <= j时) 最终结果为dp[n][w],即前n个数中是否存在一个子集的和为w。 时间复杂度为O(nw),空间复杂度为O(nw)。 以上是DP方法的详细解法,另外还有一些剪枝技巧和优化方法可以进一步提高算法效率。 ### 回答3: 这道题属于典型的0/1背包问题,可以使用动态规划来解决。 首先,我们可以定义一个二维数组dp,其中dp[i][j]表示的是在前i个数中是否可以选出若干个数,它们的和为j。可以得出以下两个状态转移方程: 当wi > j时,dp[i][j] = dp[i-1][j] 当wi ≤ j时,dp[i][j] = dp[i-1][j-wi] || dp[i-1][j] 其中“||”表示逻辑或运算。 这两个状态转移方程的含义为: 如果当前要加入的数wi大于当前子集的和j,那么它不能被选中,这种情况下dp[i][j]等于dp[i-1][j],即前i-1个数可以凑出当前子集的和j,那么前i个数同样可以凑出。 如果当前要加入的数wi小于等于当前子集的和j,我们有两种选择:不选wi,那么dp[i][j]就等于dp[i-1][j];选wi,这种情况下dp[i][j]等于dp[i-1][j-wi],表示在前i-1个数中可以凑出当前子集的和j-wi,那么再加上wi就可以凑出j,这种情况也可以凑出当前子集的和j。 最终的答案就是dp[n][w],即在前n个数中是否可以选出若干个数,它们的和为w。如果dp[n][w]为true,那么可以找到一个子集满足条件;如果dp[n][w]为false,那么不存在这样的子集。 时间复杂度为O(nw),可以通过此题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值