Subset sum Problem

本文探讨了子集求和问题的动态规划解决方案,并通过一个示例代码详细介绍了如何使用DP来找出能组成特定目标值的数的组合。此外,还提供了一种回溯的方法来寻找所有可能的组合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出一个集合和一个数值total,输出用哪几个数可以组出total。

参考链接:http://algorithms.tutorialhorizon.com/dynamic-programming-subset-sum-problem/

DP方程为
dp[i][j]=

  • dp[i-1][j] if a[j]>j
  • dp[i-1][j-a[j]] if a[j]<=j

方程的形式同背包问题如出一辙,只不过这个不涉及到重量、价值问题,而只涉及能不能放下【确切的说应该是放满】

这里写图片描述

本来是想拿这个去做Combination Sum的,发现那个是回溯而并不是DP。

至于取出所有可能的集合,我写了一个DFS去递归寻找可能的解。
不过可能不是很严谨

正确求法:

  • Start from the bottom-right cor­ner and back­track and check from the True is coming.
  • If value in the cell above if false that means cur­rent cell has become true after includ­ing the cur­rent ele­ment. So include the cur­rent ele­ment and check for the sum = sum — cur­rent element.

求路径

class Solution {
public:
        // bool dp[n][target+1];//dp[i][j]表示放入前i个物品,容量为j的时候最大价值
    bool dp[1010][1010];
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        //01背包
        int n=candidates.size();
        //使之有序
        sort(candidates.begin(),candidates.end());
        memset(dp,0,sizeof(dp));
        //初始化第一行数据
        for(int i=0;i<n;i++) dp[i][0]=true;

        for(int i=0;i<n;i++){
            //背包容量遍历
            for(int j=1;j<=target;j++){
                if(candidates[i]==j) dp[i][j]=true;
                else if(candidates[i]>j) dp[i][j]=dp[i-1][j];
                else{
                    if(i>0)
                    dp[i][j]=dp[i-1][j-candidates[i]];
                    else 
                    dp[i][j]=false;
                }
            }
        }

        for(int i=0;i<n;i++){
            //背包容量遍历
            for(int j=1;j<=target;j++){
                printf("%d ",dp[i][j]);
            }
            printf("\n");
        }
        printf("\n");

        vector<vector<int> > result;
        vector<int> temp;
        dfs(temp,candidates,n-1,target,result);
        return result;
        // //得到dp数组之后,需要遍历一下dp[i][target]==true的地方开始,向后回溯找所有的数值
    }

    void dfs(vector<int> &temp,vector<int>& candidates,int start,int capacity,vector<vector<int> >& result){
        //已经装满了
        if(capacity==0){
            result.push_back(temp);
            return;
        }

        //从后往前找
        for(int i=start;i>=0;i--){
            //说明这一栏是true
            if(dp[i][capacity]){
                //防止从后往前
                // if(capacity-candidates[i] <= candidates[i]){
                    temp.push_back(candidates[i]);
                    dfs(temp,candidates,start-1,capacity-candidates[i],result);
                    temp.pop_back();
                // }
            }

        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值