NYOJ 整数划分(三) (划分数大集合)

题意:虽然是中文题意但是还是想上一下题
题目描述
整数划分是一个经典的问题。请写一个程序,完成以下要求。
输入
每组输入是两个整数n和k。(1 <= n <= 50, 1 <= k <= n)
输出
对于输入的 n,k;
第一行: 将n划分成若干正整数之和的划分数。
第二行: 将n划分成k个正整数之和的划分数。
第三行: 将n划分成最大数不超过k的划分数。
第四行: 将n划分成若干个 奇正整数之和的划分数。
第五行: 将n划分成若干不同整数之和的划分数。

第六行: 打印一个空行

将n划分成若干个正整数之和: 
我们设dp[i][j]表示的是,当前的数字是i,且最大的划分是j的时候的划分数
初始化:dp[][1] = 1, dp[1][] = 1 , 当一个数的最大划分是1的时候也就是他全部都是1,或者当前数字是1的时候只能由一种划分
转移方程:

  dp[i][j] = dp[i][j-1] + dp[i-j][j](i>=j) 
   dp[i][j] = dp[i][i] (i<j) 

解释一下这个转移方程,当前数字为i最大划分是j可以由当前数字为i最大划分为j-1转换过来,(4,3) {1,3},{2,2}, (4,2) {1,2,1,},{2,2}是吧其实就是等于把那个大的在划分一下,还可以由i-j 和 j转移过来 (6,3) {3,3} (9,3) {3,3,3},其实就是前一个状态在加上一个j得来的。大概就是这个意思把。
(二)
将n划分成k个正整数之和的划分数(这个其实就是给你n个苹果和m个盘子而且盘子不能为空,问你最多有多少种分发)
我们设dp[i][j] 表示的是 当前还剩下n个苹果和m个盘子的时候的最大值
初始化: dp[][1] = 1,当他只剩下一个盘子的时候,就只有一种分法。
状态转移方程:
dp[i][j] = dp[i-j][j] + dp[i-1][j-1] (i>=j) 


解释一下这个转移方程,你剩下i个苹果m个盘子的时候,那么下一次你放的时候,可以在每个盘子里都放一个苹果,他的转移方程就是dp[i-j][i],当前剩下i-j个苹果(因为每个盘子都放了一个,总共有j个盘子,之后盘子数量还是那么多)或者你只在一个盘子里面放一个苹果,之后就不管这个盘子了,那么他是dp[i-1][j-1],放了一个苹果所以i-1 ,丢了一个盘子j-1。
(三)
将n划分成不超过k的最大划分数
这个其实和第一个是一样的,状态转移方程也一样,这是返回值不一样而已,你仔细看看第一个对于dp数组的定义其实就是这个东西,不多说了好吧
(四)
将n划分成为几个奇正整数之和的划分数
我们设dp[i][j] 表示的是i这个数划分的最大值不超过k的时候的划分数,其实和第一个差不多就是这里有一个限制就是要是奇数
初始化:dp[][1] = 1 ;
转移方程:
当j为奇数的时候
dp[i][j] = dp[i-j][j] + dp[i][j-1];
dp[i][j] = dp[i][i];

当j为偶数的时候
dp[i][j] = dp[i][j-1]
解释一下转移方程,当他是奇数的时候,其实和第一个是一样的,但是只是奇数的时候才是一样的,当他是偶数的时候,我们知道j-1 是奇数,所以他是由dp[i][j-1] 转移过来的。
(五)
将n划分成几个不相同的正整数之和。
我们设dp[i][j]表示的是n这个数划分的最大值不超过k的划分数
初始化:
dp[][1] = 1; dp[1][] = 1,当他的最大划分为1的时候也就是说所有数都是1方案数是1,当他是1的时候,方案数也是1
转移方程 :
dp[i][j] = dp[i-j][j-1] + dp[i][j-1] (i>=j)
dp[i][j] = dp[i][i] (i<j)

解释一下转移方程,他说的是不能重复,所以当前数字是i,最大划分为j的时候,可以划分出一个j,又因为他不能重复,所以只能划分出一个j,划分完就不能用了,所以是dp[i-j][j-1](划分完了),其他的都一样,他可以把j在划分一个1
总结完了上代码把(感觉自己的认知还是不深刻。。。要在看一下别人的博客呢)

#include <bits/stdc++.h>
using namespace std;
#define mes(a) memset(a,0,sizeof(a));
int n,k;
int a()//将n划分成若干正整数之和的划分数
{
	int dp[55][55];
	mes(dp);
	dp[0][0] = 1;
	for(int i = 0 ; i < 55;i++)
	{
		for(int j = 1 ; j < 55; j++)
		{
			if(i>=j)
			{
				dp[i][j] = dp[i-j][j] + dp[i][j-1];
			}
			else 
			{
				dp[i][j] = dp[i][i];
			}
		}
	}
	return dp[n][n];
}
int b()//将n划分成k个正整数之和的划分数。
{
	int dp[55][55];
	mes(dp);
	dp[1][1] =1;
	for(int i = 2 ; i <= 51 ; i++)
	{
		for(int j = 1 ; j <= i ; j++)
		{
			dp[i][j] = dp[i-1][j-1]+dp[i-j][j];
		}
	}
	return dp[n][k];
	
}
int c()//将n划分成若干正整数之和的划分数
{
	int dp[55][55];
	mes(dp);
	dp[0][0] = 1;
	for(int i = 0 ; i < 55 ; i++)
	{
		for(int j = 1 ; j < 55 ; j++)
		{
			if(i>=j)
			{
				dp[i][j] = dp[i-j][j] + dp[i][j-1];
			}
			else 
			{
				dp[i][j] = dp[i][i];
			}
		}
	}
	return dp[n][k];
}
int d()
{
	int dp[55][55];
	mes(dp);
	for(int i = 0 ; i <  55 ; i++)
	{
		dp[i][1] = 1;
		if(i&1)
		{
			dp[0][i] = 1;
		}
	}
	for(int i = 1 ; i < 55 ; i++)
	{
		for(int j = 1 ; j < 55 ; j++)
		{
			if(j&1)
			{
				if(i>=j)
				{
					dp[i][j] = dp[i-j][j] + dp[i][j-1];
				}
				else dp[i][j] = dp[i][i];
			}
			else 
			{
				dp[i][j] = dp[i][j-1];
			}
		}
	}
	return dp[n][n];
}
int e()
{
	int dp[55][55];
	mes(dp);
	dp[0][0] = 1;
	for(int i = 0 ; i < 55 ; i++)
	{
		for(int j = 1 ; j < 55 ; j++)
		{
			if(i>=j)
			{
				dp[i][j] = dp[i-j][j-1] + dp[i][j-1];
			}
			else 
			{
				dp[i][j] = dp[i][i];
			}
		}
	}
	return dp[n][n];
}
int main()
{
	while(cin>>n>>k)
	{
		printf("%d\n%d\n%d\n%d\n%d\n",a(),b(),c(),d(),e());
		puts("");
	}
}


全部评论

相关推荐

自从我室友在计算机导论课上听说了“刷&nbsp;LeetCode&nbsp;是进入大厂的敲门砖”,整个人就跟走火入魔了一样。他在宿舍门口贴了一张A4纸,上面写着:“正在&nbsp;DP,请勿打扰,否则&nbsp;Time&nbsp;Limit&nbsp;Exceeded。”日记本的扉页被他用黑色水笔加粗描了三遍:“Talk&nbsp;is&nbsp;cheap.&nbsp;Show&nbsp;me&nbsp;the&nbsp;code。”连宿舍聚餐,他都要给我们讲解:“今天的座位安排可以用回溯算法解决,但为了避免栈溢出,我建议用动态规划。来,这是状态转移方程:dp[i][j]&nbsp;代表第&nbsp;i&nbsp;个人坐在第&nbsp;j&nbsp;个位置的最优解。”我让他去楼下取个快递,他不直接去,非要在门口踱步,嘴里念念有词:“这是一个图的遍历问题。从宿舍楼(root)到驿站(target&nbsp;node),我应该用&nbsp;BFS&nbsp;还是&nbsp;DFS?嗯,求最短路径,还是广度优先好。”和同学约好出去开黑,他会提前发消息:“集合点&nbsp;(x,&nbsp;y),我们俩的路径有&nbsp;k&nbsp;个交点,为了最小化时间复杂度,应该在&nbsp;(x/2,&nbsp;y/2)&nbsp;处汇合。”有一次另一个室友低血糖犯了,让他帮忙找颗糖,他居然冷静地分析道:“别急,这是一个查找问题。零食箱是无序数组,暴力查找是&nbsp;O(n)。如果按甜度排序,我就可以用二分查找,时间复杂度降到&nbsp;O(log&nbsp;n)。”他做卫生也要讲究算法效率:“拖地是典型的岛屿问题,要先把连通的污渍区块都清理掉。倒垃圾可以用双指针法,一个指针从左往右,一个从右往左,能最快匹配垃圾分类。”现在我们宿舍的画风已经完全变了,大家不聊游戏和妹子,对话都是这样的:“你&nbsp;Two&nbsp;Sum&nbsp;刷了几遍了?”“别提了,昨天遇到一道&nbsp;Hard&nbsp;题,我连暴力解都想不出来,最后只能看题解。你呢?”“我动态规划还不行,总是找不到最优子结构。今天那道接雨水给我整麻了。”……LeetCode&nbsp;真的害了我室友!!!
老六f:编程嘉豪来了
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务