回溯算法-定和子集问题


问题描述:在一给定集合中,选择出其子集,使得该子集的元素之和等于给定的数。选择的子集个数不一定唯一。

数学模型:
数的集合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;
}

回溯算法-定和子集问题_第1张图片

你可能感兴趣的:(算法思想,C语言,算法)