【回溯法】C++子集和数问题

题目描述

(子集和数问题) 已知n+1个正数:wi,1≤i≤n,和M。要求找出wi的和数是M的所有子集。例如,若n=4,(w1,w2,w3,w4)=(11,13,24,7),M=31,则满足要求的子集是(11,13,7)和(24,7)

思路

通过回溯法递归求解大小为1-n的子集

// 该算法为求某个m大小的子集的经典模板
// t为遍历到的层数,m为子集的大小,c为当前元素下标
backtrack(int t,int c){
	if(t==m){
		ans.push_back(res);
		return;
	}else{
		// n为集合大小
		for(int i=c;i<n;i++){
			// nums是集合
			res.push_back(nums[i]);
			backtrack(t+1,i+1);
			res.pop_back();
		}
}

代码

#include "stdafx.h"
#include<iostream>
#include<vector>
using namespace std;
#define n 4

int M=31;
int nums[n]={11,13,24,7};
void bt(int t,int m,int idx,int &sum,vector<int> &res){
	if(t==m){
		if(sum==M){
			ans.push_back(res);
			for(int j=0;j<res.size();j++)
				cout<<res[j]<<' ';
			cout<<endl;
		}
		return;
	}else{
		for(int i=idx;i<n;i++){
			res.push_back(nums[i]);
			sum+=nums[i];
			bt(t+1,m,i+1,sum,res);
			sum-=nums[i];
			res.pop_back();
		}
	}
}


int main(){
	int m=3;
	int sum=0;
	vector<int> res;
	for(int m=1;m<=n;m++){
		bt(0,m,0,sum,res);
	}
}


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
子集问题是一个经典的组合优化问题,可以使用回溯法(backtracking)进行求解。具体的思路是: 1. 定义一个组或者集合,存储所有可选的值。 2. 定义一个组或者集合,存储当前已选的值。 3. 定义一个变量,记录当前已选值的和。 4. 从第一个开始,遍历可选值,对于每个可选值,判断是否可以加入已选值中。如果可以,则加入已选值中,更新当前和,并且递归调用解决剩余问题;如果不可以,则不加入已选值中,继续遍历下一个可选值。 5. 当已选值的和等于目标值时,输出当前已选值,结束递归。 6. 当所有可选值都遍历完毕,仍未找到解,则回溯到上一个节点,继续遍历下一个可选值。 下面是 C 语言实现的示例代码: ```c #include <stdio.h> #define MAX_NUM 100 int nums[MAX_NUM]; int selected[MAX_NUM]; int sum, target; int n; void subset_sum(int k) { if (sum == target) { printf("Subset found: "); for (int i = 0; i < n; i++) { if (selected[i]) { printf("%d ", nums[i]); } } printf("\n"); return; } if (k == n || sum > target) { return; } selected[k] = 1; sum += nums[k]; subset_sum(k + 1); sum -= nums[k]; selected[k] = 0; subset_sum(k + 1); } int main() { printf("Enter the number of elements: "); scanf("%d", &n); printf("Enter the elements: "); for (int i = 0; i < n; i++) { scanf("%d", &nums[i]); } printf("Enter the target sum: "); scanf("%d", &target); subset_sum(0); return 0; } ``` 在实际应用中,为了避免重复计算,可以使用记忆化搜索或者动态规划进行优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值