回溯法之子集和问题

来源:互联网 发布:c 对端口的访问被拒绝 编辑:程序博客网 时间:2024/06/11 12:44

问题描述:设集合S={x1,x2,…,xn}是一个正整数集合,c是一个正整数,子集和问题判定是否存在S的一个子集S1,使S1中的元素之和为c。试设计一个解子集和问题的回溯法。将子集和问题的解输出。当问题无解时,输出“No Solution!”。

因为我在代码里的注释已经写了很多了,大家将就看着注释理解哈吐舌头

直接贴代码:

#include<iostream>using namespace std;#define N 10000int n, c, rest = 0;//rest表示从当前元素加到最后一个元素的总和,用来回溯时判断限界剪枝  int a[N];//a[N]存储S集合元素 ,最多可以存储N个 int x[N] = {0};//设置x[N]来表示a[N]元素是否选择,初始为0,若为1则表示选择 int sum = 0;//当前所选元素之和bool backtrack(int t)//调用这个方法判断是否有解 {       if( sum == c )         return true; // 找到可行解       if( t > n )         return false ;//找不到可行解       rest-=a[t];       if(sum + a[t] <= c)//可以取a[t],在子集树中表示走左分支         {                x[t] = 1 ;//选择a[t] ,赋值为1                 sum = sum+a[t] ;                if ( backtrack(t+1) )                        return true;                sum -= a[t];//回溯时要把之前加的减掉         }        if( sum + rest >= c) //没办法确实不行,利用rest判断限界剪枝 ,在子集树中表示走右分支         {                x[t] = 0 ;                if ( backtrack(t+1) )                        return true;        }         rest += a[t];//把之前减掉的加回来         return false;//当层遍历后发现没有解决方案,返回false回去上一层}int main(){        cin >>n>>c;//初始化集合元素个数n和目标值c         for (int i = 1; i <= n; i++)        {                cin >> a[i];//依次输入a[i]                 rest += a[i];//初始值为全部元素之和        }        if (!backtrack(1)) cout << "No Solution!";//无解决方案         else                for( int i = 1; i <= n; i++)                        if ( x[i] )//若为1则表示选择了                          cout << a[i] << " ";                cout << endl;         return 0;}

谢谢阅读,欢迎讨论建议或指正吐舌头


0 0
原创粉丝点击