整数拆分【清华大学复试机试题】【动态规划】

题目描述

一个整数总可以拆分为2的幂的和,例如: 7=1+2+4 7=1+2+2+2 7=1+1+1+4 7=1+1+1+2+2 7=1+1+1+1+1+2 7=1+1+1+1+1+1+1 总共有六种不同的拆分方式。 再比如:4可以拆分成:4 = 4,4 = 1 + 1 + 1 + 1,4 = 2 + 2,4=1+1+2。 用f(n)表示n的不同拆分的种数,例如f(7)=6. 要求编写程序,读入n(不超过1000000),输出f(n)%1000000000。

输入描述:

每组输入包括一个整数:N(1<=N<=1000000)。

输出描述:

对于每组数据,输出f(n)%1000000000。

示例1

输入

复制

7

输出

复制

6

递推公式:

如果i是奇数,i=1+(i-1),所以f(i)=f(i-1)

如果i是偶数,f(i)=f(i-1)+f(i/2) 此时i的所有划分中有两种情况,一种是包含1,一种是不包含1(我在这里看别人的思路就不太懂,

包含1:i=1+(i-1) :在i-1的每个划分中,给他加上一个1

不包含1:i=2*(i/2):对于i/2的每个划分,对划分中的每个数乘2,这样整个划分中就不会有1了。

举个例子,6的不包含1的划分:

  • 3的划分:  1+1+1、1+2
  • 6:          2+2+2、2+4(对3的划分中的每个元素都乘2,这样得出来的划分不会出现1)
#include

using namespace std;

long long f[1000005];
int main(){
	int n;
	while(scanf("%d",&n)!=EOF){
		f[1]=1;
		for(int i=2;i<=n;i++){
			if(i%2) f[i]=f[i-1];
			else f[i]=(f[i-1]+f[i/2])%1000000000;
		}
		printf("%lld\n",f[n]);
	}
	return 0;
}

动态规划:

本题是要将一个整数拆分为2的幂的和,即将n拆分成2^0,2^1,2^2,2^3……2^19,然后正好组成数n。可以理解为:一个背包容量为n,有20种物品,每种物品个数不限,体积分别为2^0,2^1,2^2,2^3……2^19,求有多少种方案能恰好把背包装满,即完全背包问题

int a[20]={2^0,2^1,……2^19};

状态转移方程:

dp[i][j]表示用前j个数字,组成i的方案个数,此时就分为两种情况

  • 不用第j个数字   dp[i][j]=dp[i][j-1]
  • 用第j个数字      dp[i-a[j]][j]   

此时不再是求哪种方案价值最大,而是总的方案个数,所以不用max,而是相加

dp[i][j]=dp[i][j-1]+dp[i-a[j]][j]

转换为一维数组 dp[i]=dp[i]+dp[i-a[j]]   (j要从前往后遍历)

边界:

dp[0]=1

dp[1~n]=0

#include

using namespace std;

long long dp[1000005];
int main(){
	long long a[21];
	a[0]=1;
	for(int i=1;i<20;i++){
		a[i]=a[i-1]<<1;
	}
	int n;
	while(scanf("%d",&n)!=EOF){
		for(int i=0;i<=n;i++){
			dp[i]=0;
		} 
		dp[0]=1;
		for(int j=0;j<20;j++){  //20种 
			for(int i=a[j];i<=n;i++){
				dp[i]=(dp[i]+dp[i-a[j]])%1000000000;
			} 
		}
		printf("%lld\n",dp[n]);
	}
	return 0;
}

 

你可能感兴趣的:(考研机试题,dp)