2019蓝桥真题--质数拆分(动态问题01背包)

题目:质数拆分
将 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;
				}
			}
			
		}
	}

}```

你可能感兴趣的:(动态规划,算法,java)