input.txt
5 10
2 4 6 5 2
#include <iostream>
#include <fstream>
using namespace std;
class subset{
public:subset(int* best, int* arr, int n, int result);
void backtrack();
bool Place(int k);
int* arr;//序列各个个数的值
int n;//数字总个数
int *x;//当前解
int *best;//最优解
int r;//剩下的序列和
int nresult;//当前序列的总和
int result;//目的序列和
};
subset::subset(int* best, int* arr, int n, int result){
this->best = best;
this->arr = arr;
this->n = n;
this->result = result;
x = new int[n + 1];
r = 0;
for (int i = 0; i < n; i++){
r += arr[i];
}
}
bool subset::Place(int k){//第k个不装的情况下当前序列和剩下的和是否能组成result
if ((nresult + r) < result)return false;
return true;
}
void subset::backtrack(){//向左孩子出生条件nresult+arr[k]<result,右孩子出生条件Place()
x[1] = 0;
int k = 1;
nresult = 0;
//搜索子树
while (true){
while ((k <= n) && (nresult + arr[k] <= result)){//从k节点开始一直向左
r -= arr[k];
nresult += arr[k];
x[k] = 1;
k++;
}
if (k > n){//到达终点
if (nresult == result){//找到节点结束
for (int j = 1; j <= n; j++){
best[j] = x[j];
}
return;
}
else{//返回到最后后一次进入队列的节点
k--;//退回到叶子节点
r += arr[k];//释放资源
nresult -= arr[k];//释放资源
k--;//找最后一次加入的节点
while (k > 0 && !x[k]){//从右子树返回
r += arr[k];
k--;
}
nresult -= arr[k];
x[k] = 0;
k++;
}
}
else{//进入右子树
r -= arr[k];
x[k] = 0;
k++;
}
}
}
int main(){
//数据读取
ifstream in("input.txt", ios::in);
if (!in.is_open()){
cout << "Error opening file";
exit(1);
}
char ch;
int n = in.get() - '0';//子集个数
while ((ch = in.get()) != ' '){
n = n * 10 + ch - '0';
}
int* arr = new int[n+1];
int result = in.get() - '0';//记录序列和
while ((ch = in.get()) != '\n'){
result = result * 10 + ch - '0';
}
int i = 1;
while (!in.eof()){
arr[i] = in.get() - '0';
while( ((ch = in.get()) != ' ')&&(ch!= '\n')&&(ch!=-1)){
arr[i] = arr[i] * 10 + ch - '0';
}
i++;
}
/*
for (int i = 0; i < n; i++){
cout << arr[i] << " " << endl;
}
*/
in.close();
//数据处理
int* best = new int[n+1]();//标记最优解
subset demo(best,arr,n,result);
demo.backtrack();
for (int i = 1; i <= n; i++){
if (best[i] == 1)cout << arr[i] << endl;
}
return 0;
}