问题描述:在一给定集合中,选择出其子集,使得该子集的元素之和等于给定的数。选择的子集个数不一定唯一。
数学模型:
数的集合S={w1,w2,…,wn};
定数:M;
求解向量: x=(x1,x2,…,xn),xi为0或1, 使得wi*xi==M.
约束条件:
1、假定前k-1项选择已经确定,并且第k项已选择,使得wi*xi<=M;
(i从1至k)
2、确定是否需要继续向前搜索:
当wi*xi==M时,已达到答案节点,回溯,搜寻其它的解;
当wi*xi< M时
继续向前搜索的条件是B(k+1):
wi*xi>=M (i从1至n)
且wi*xi<=M(i从1至k+1)
(假定w1,w2,…,wn按不降顺序排列)
// BackTrackAlgorithm_SumSubSet.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
int M = 30, n = 6;//M为总和,n为子集的元素个数
float W[6] = { 5,10,12,13,15,18 };//集合
bool X[6] = {};//1为选择,0为不选择
int flag = 0;
void SumSubSet(float s, int k, float r)
{
float sum = 0;
X[k] = 1; //生成左子树
if (s + W[k] == M)
{
flag++;
for (int i = 0; i <= k; i++)
{
printf("X[%d}==%d\t", i, X[i]);
}
printf("\n");
for(int i = 0; i <= k; i++)
{
if (X[i] == 1)
{
printf("W[%d]==%.0f\t", i, W[i]);
sum += W[i];
}
}
printf("\n该选择子集的总和为:%.0f\n", sum);
sum = 0;
printf("\n**************************************************\n\n");
}
else if (s + W[k]+W[k+1]<=M)
{
SumSubSet(s + W[k], k + 1, r - W[k]);
}
if (s + r - W[k] >= M && s + W[k + 1] <= M)
{
X[k] = 0; //生成右子树
SumSubSet(s, k + 1, r - W[k]);
}
}
int main()
{
int k=0;
float s = 0, r = 73;
printf("M==%.0f\t ", M);
printf("n==%d \n", n);
for (int i = 0; i < n; i++)
printf("W[%d]==%.0f\t",i, W[i]);
printf("\n\n采用回溯算法求解该定和子集问题:\n\n");
SumSubSet(s, k, r);
printf("++++++++++++++++共有%d种方案.++++++++++++++++\n\n\n",flag);
return 0;
}