问题描述
2019可以被分解成若干个两两不同的素数,请问不同的分解方案有多少种?
注意:分解方案不考虑顺序,如 2 + 2017 = 2019 和 2017 + 2 = 2019 属于同一种方案。
答案:
55965365465060
方案一:0、1背包问题
每个数有选或者不选两种方案。
对于每次循环的质数,都有两种方案,不选或者选。
可以推出f[i][j] = f[i-1][j] + f[i-1][j+a[i]];
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int N = 2020;
bool book[N];
long long f[N][N];
vector<int> a;
bool prime(int num){
if(num == 2){
return true;
}
for(int i = 2; i <= sqrt(num); i ++){
if(num % i == 0){
return false;
}
}
return true;
}
int main(){
a.push_back(0);//多放置一个,防止之后越界问题
for(int i = 2; i <= 2017; i ++){
if(prime(i)){
a.push_back(i);
}
}
int len = a.size();
f[0][0] = 1;
for(int i = 1; i <= len; i ++){//核心代码
for(int j = 0; j <= 2019; j++){
f[i][j] = f[i-1][j];
if(j >= a[i]){
f[i][j] += f[i - 1][j - a[i]];
}
}
}
cout << f[len-1][2019] << endl;
return 0;
}
优化空间
利用0、1背包问题的优化方案可以优化
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int N = 2020;
long long f[N];
vector<int> a;
bool prime(int num){
if(num == 2){
return true;
}
for(int i = 2; i <= sqrt(num); i ++){
if(num % i == 0){
return false;
}
}
return true;
}
int main(){
for(int i = 2; i<=2019;i++){
if(prime(i)){
a.push_back(i);
}
}
int len = a.size();
f[0] = 1;
for(int i = 0; i < len; i ++){
for(int j = 2019; j >=a[i]; j --){
f[j] += f[j-a[i]];
}
}
cout << f[2019] << endl;
return 0;
}