这是我的代码,打印子集的元素,其总和等于给定的总和,(它仅适用于正数):
#include <bits/stdc++.h>
using namespace std;
void traverse(vector<int> vec) {
for(int a=0; a < vec.size(); a++)
cout << vec[a] << " ";
cout << endl;
}
void possible(vector<int> vec, int sum, vector<int> now) {
if(sum == 0) {
traverse(now);
}
else if(sum < 0) {
now.clear();
}
else if(sum > 0 && vec.size() > 0) {
for(int a = 0; a < vec.size(); a++) {
now.push_back(vec[a]);
vector<int> vecc(vec.begin() + a + 1, vec.end());
possible(vecc, sum - vec[a], now);
now.erase(now.end() - 1);
}
}
}
int main() {
int n, sum;
cin >> n >> sum;
vector<int> vec(n), now;
for(int a = 0; a < n; a++)
cin >> vec[a];
possible(vec, sum, now);
return 0;
}
是否有任何改进机会或更快的方法来改善运行时间?
任何动态问题解决方案?
答案 0 :(得分:3)
子集总和问题可以通过动态编程来解决,因为您可以在https://github.com/eclipse/paho.mqtt.m2mqtt/blob/master/M2Mqtt/M2Mqtt.NetMf43.csproj中阅读。
问题实际上是NP-Complete(此问题没有已知的多项式时间解决方案)。上面的链接提供了两种解决方案,其中第二种解决方案可以解决伪多项式时间中的问题。
作为技术优化,您可以更改此内容:
void traverse(vector<int> vec)
到此:
void traverse(vector<int>& vec)
以避免可能较大的矢量的非自然副本。如果可以的话,为你的所有功能做到这一点。
在启用警告的情况下编译代码(例如,GCC为-Wall -Wextra
),并修复这些警告。然后考虑表现。
答案 1 :(得分:1)
一种似乎有效的递归动态编程解决方案(虽然我还没有彻底测试过)。它也适用于负数。
// To make it simple, returns empty vector if no solution was found
// and also if the sum is zero
std::vector<int> find(const std::vector<int>& numbers, int sum)
{
std::vector<int> result;
if (findNumbersMakingSum(numbers, sum, result, 0)) {
return result;
} else {
return std::vector<int>();
}
}
bool findNumbersMakingSum(
const std::vector<int>& numbers,
int sumLeft,
std::vector<int>& takenNumbers,
size_t position)
{
if (!sumLeft) {
// We're done
return true;
}
if (position == numbers.size()) {
return false;
}
int current = numbers[position];
if (!current) {
// Just skip zero elements
return findNumbersMakingSum(numbers, sumLeft, takenNumbers, position + 1);
}
// Case 1: take number at current position:
std::vector<int> taken = takenNumbers;
taken.push_back(current);
if (findNumbersMakingSum(numbers, sumLeft - current, taken, position + 1)) {
takenNumbers = std::move(taken);
return true;
}
// Case 2: don't take number at current position
return findNumbersMakingSum(numbers, sumLeft, takenNumbers, position + 1);
}
由于它是递归的,因此有大量输入会因为有限的调用堆栈而失败。解决方案可以很容易地更新,不使用递归,但我希望这个想法很明确。
答案 2 :(得分:0)
关于子集和问题的this维基百科文章中提到了动态编程解决方案;它通过获取状态空间的两个轴来使用目标值的“组合化”。第一个轴是项目的初始间隔,而第二个轴是期望的目标值。