这个题目让我感受到了算法的魅力。
写的第一个解法跑一个n = 684的用例,需要100个小时才能出结果;当放弃第一个解法另换思路后,第二个解法就可以满足题目要求,1秒内出结果。下面给出两种解法,但是只介绍第二种解法思想。
首先将n个数划分成两部分(代码中后缀用Left和Right表示),分别在这两部分中取数,计算和为0至sum的方案数(其中和为0的方案数固定为1(因为一个数都不取的这种方案,和为0)),将结果保存在两个大小为sum+1的数组中。根据这两个数组可以合成一个数组(合成方法见代码),这个数组中存放了n个数中取数,和为0至sum的方案数。输出和为sum的方案数即可。
第一种解法代码:
#include<iostream> #include<algorithm> #include<vector> using namespace std; // 第一种解法,算法复杂度高 void mycalnumproposal(vector<int> avec, int sum, int &numproposal) {//这样做算法复杂度太大,跑示例得跑100多个小时,要求算法1秒内完成,可见优秀算法的必要和重要性 if (sum == 0) { numproposal++; return; } int n = avec.size(); vector<int> avectemp(avec); for (int k = 0; k < n; k++) { // 递归里面加循环不是明智的选择 int sumtemp = sum - avec[k]; if (sumtemp < 0)continue;//return; // return对应排序序列;continue对应普通序列 else { avectemp.erase(avectemp.begin(), avectemp.begin() + 1); mycalnumproposal(avectemp, sumtemp, numproposal); } } } int main() { int n, sum; int a; vector<int> avec; cin >> n >> sum; for (int i = 0; i < n; i++) { cin >> a; avec.push_back(a); } //sort(avec.begin(), avec.end()); // 排序也需要时间 int numproposal = 0; mycalnumproposal(avec, sum, numproposal); cout << numproposal << endl; return 0; }
第二种解法代码:
#include<iostream> #include<vector> using namespace std; vector<long> mycalNumProposal2(vector<long> nvec, long sum) { vector<long> mvec(sum+1,0);mvec[0] = 1; if (nvec.size() == 1) { if(nvec[0] <= sum) mvec[nvec[0]] = 1; return mvec; } int k = nvec.size() / 2; vector<long> nvecLeft(nvec); nvecLeft.erase(nvecLeft.begin() + k, nvecLeft.end()); vector<long> nvecRight(nvec); nvecRight.erase(nvecRight.begin(), nvecRight.begin() + k); vector<long> mvecLeft(sum+1, 0); vector<long> mvecRight(sum+1, 0); mvecLeft = mycalNumProposal2(nvecLeft, sum); mvecRight = mycalNumProposal2(nvecRight, sum); for (long i = 1; i <= sum; i++) { for (long j = 0; j <= i; j++) { mvec[i] += mvecLeft[j] * mvecRight[i - j]; } } mvec[0] = 1; return mvec; } int main() { int n; long sum; long a; vector<long> nvec; cin >> n >> sum; for (long i = 0; i < n; i++) { cin >> a; nvec.push_back(a); } vector<long> mvec; mvec = mycalNumProposal2( nvec, sum); cout << mvec[sum] << endl; return 0; }