「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战」。
这是蓝桥杯20年省赛的一道题,题目难度设置为中等。这道题是不能用暴力搜索来做的,一定会超时。很多人也许能够想到用动态规划来做,但是却联想不到01背包上,做不出这道题目。题目的难点就在这里。下面让我们用01背包来解出这道题。
题目
2019可以由若干个质数的和构成,并且这些质数两两不同。比如2019=2+2017,这是一个情况,并且2017+2与刚才的是同一种。求出所有的情况个数。
思路
这道题其实就是个01背包问题,让我们来将这道题与01背包联想一下。首先,我们先找出2019这个数以内所有的质数,这些质数就是我们拼接成2019的东西,因为我们要的质数两两不同,所以每种质数我们最多取一种,那这个不就是01背包问题吗?但是这个跟我们常写的01背包有些许的不同,所以我们要稍微修改一下。背包容量我们取的就是1到2019,但是我们不是要求最大值,这里物品就是2019以内的质数,但是物品是没有权值的,我们要求的是在指定物品内能否构成这个数。质数2,3,5,7,11,.....存储在m数组中。例如dp[1][2],这里指在前一个物品中能否满足质数和是2,自然满足,所以dp[1][2]=1,dp[2][2]=dp[1][2]+dp[2-1][2-m[2]]。和普通01背包的操作是一样的。
总代码
#include <bits/stdc++.h>
using namespace std;
int p[2000];
long long dp[3000][3000];
bool ifs(int a){
int b=(int)sqrt(a);
for(int i=2;i<=b;i++){
if(a%i==0)
return false;
}
return true;
}
int main()
{
int p[2000];
int cnt=0;
for(int i=2;i<=2019;i++){
if(ifs(i)){
p[++cnt]=i;
}
}
dp[0][0]=1;
for(int i=1;i<=2019;i++){
dp[0][i]=0;
}
for(int i=1;i<=cnt;i++){
for(int j=0;j<=2019;j++){
dp[i][j]=dp[i-1][j];
if(p[i]<=j){
dp[i][j]=dp[i][j]+dp[i-1][j-p[i]];
}
}
}
cout<<dp[cnt][2019];
return 0;
}