题目:质数拆分
将 2019 拆分为若干个两两不同的质数之和,一共有多少种不同的方法?
注意交换顺序视为同一种方法,例如2+2017=2019 与 2017 + 2 = 2019 视为同一种方法。
注:做题一定仔细读题,之前没看到两两不同,结果在哪里解了半天没解出来。
题解:
把2019拆分,反过来就是用若干个不同的质数组成值为2019的数。
每个数只取一次,刚好符合01背包问题。用f[i][j]表示用前i个数组成重量为j的方法数量,所以先打个素数表。
优化后的素数筛:
public static void sushubiao() {
a[1]=true;//false代表i为素数。
for (int i = 2; i*i < a.length; i++) {
if(!a[i]) {
for(int j = i*i;j<a.length;j+=i) {
a[j]=true;
}
}
}
}
打表:
int[] w = new int[2020];
int k=1;
for(int i =2;i<2020;i++) {
if(!a[i]) {
w[k++]=i;
}
}
实现01背包:如果不懂01背包点这里01背包的实现及优化
首先如果用i-1个数可以得到j,那么用i个数肯定也可以(因为数是从小到大排列,且i包含了[i-1]),所以每步要把f[i-1][j]赋值给f[i][j]
其次判断j是否大于w[i] 如果小于那么j里面肯定没有w[i]这个组成,例如j=7比w[i=5]小 (i代表是第五个质数w[5]=9),就不可以,如果是i=3,w[i]=5,f[3][7]就要加上f[2][7-5]
代码:
long[][] dp=new long[2030][2030];
dp[0][0]=1;//dp[0][0]也是一种方法!!!!
for(int i =1;i<k;i++) {
for(int j=0;j<=2019;j++) {
dp[i][j]=dp[i-1][j];
if(j>=w[i]) {
dp[i][j]+=dp[i-1][j-w[i]];
}
}
}
System.out.print(dp[k-1][2019]);
完整代码如下:(没有优化空间,优化空间上面链接有方法)
public class Zhishu_dp {
static boolean[] a = new boolean[3000];
static long res =0;
public static void main(String[] args) {
sushubiao();
int[] w = new int[2020];
int k=1;
for(int i =2;i<2020;i++) {
if(!a[i]) {
w[k++]=i;
}
}
long[][] dp=new long[2030][2030];
dp[0][0]=1;//dp[0][0]也是一种方法!!!!
for(int i =1;i<k;i++) {
for(int j=0;j<=2019;j++) {
dp[i][j]=dp[i-1][j];
if(j>=w[i]) {
dp[i][j]+=dp[i-1][j-w[i]];
}
}
}
System.out.print(dp[k-1][2019]);
}
public static void sushubiao() {
a[1]=true;//false代表i为素数。
for (int i = 2; i*i < a.length; i++) {
if(!a[i]) {
for(int j = i*i;j<a.length;j+=i) {
a[j]=true;
}
}
}
}
}```