NOI 2.7 7219:复杂的整数划分问题

题目来源:http://noi.openjudge.cn/ch0207/7219/

7219:复杂的整数划分问题

总时间限制200ms  内存限制65536kB

描述

将正整数表示成一系列正整数之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 k>=1 
正整数的这种表示称为正整数的划分。

输入

标准的输入包含若干组测试数据。每组测试数据是一行输入数据,包括两个整数N K 
(0 < N <= 50, 0 < K <= N)

输出

对于每组测试数据,输出以下三行数据:
第一行: N划分成K个正整数之和的划分数目
第二行: N划分成若干个不同正整数之和的划分数目
第三行: N划分成若干个奇正整数之和的划分数目

样例输入

5 2

样例输出

2
3
3

提示

第一行:4+1, 3+2,
第二行: 54+13+2
第三行: 51+1+3 1+1+1+1+1+1

-----------------------------------------------------

解题思路

动态规划

1. k个正整数和

dp[i][j]: i的j个正整数划分数, dp[i][j] =dp[i-j][j]+dp[i-1][j-1]

dp[i-j][j]: i-j的j个正整数划分上每个正整数+1;

dp[i-1][j-1]: i-1的j-1个正整数划分再添上一个1

// 超级巧妙的思路哇~

2. 不同整数和

dp[i][j](1<=j<=i): 整数i的这样的划分数,其中每个划分得到的最大整数为j

dp[1][1] = 1

dp[i][j] =sum(dp[i-j][k]), 2<=k<j,  whenj<i

dp[i][j] = 1,                       when i==j

3. 正奇数和

dp[i][j]: 正整数i的这样的划分数,使得每个划分中最大的正奇数为j

dp[i][j] =dp[i-j][k], 1<=k<=j, k是正奇数

// 2. 和 3. 都是在NOI 2.7 7215:简单的整数划分问题的基础上的一点小改动

// 2. 就是求和的时候k必须小于j,不能等于j,且k要从2开始遍历

// 3.  就是j、k都是奇数

-----------------------------------------------------

代码

// 动态规划
// 1. k个正整数和
// dp[i][j]: i的j个正整数划分数, dp[i][j] = dp[i-j][j]+dp[i-1][j-1]
// dp[i-j][j]: i-j的j个正整数划分上每个正整数+1; 
// dp[i-1][j-1]: i-1的j-1个正整数划分再添上一个1
// 2. 不同整数和
// dp[i][j] (1<=j<=i): 整数i的这样的划分数,其中每个划分得到的最大整数为j
// dp[1][1] = 1
// dp[i][j] = sum(dp[i-j][k]), 2<=k<j,  when j<i
// dp[i][j] = 1,						when i==j
// 3. 正奇数和
// dp[i][j]: 正整数i的这样的划分数,使得每个划分中最大的正奇数为j
// dp[i][j] = dp[i-j][k], 1<=k<=j, k是正奇数

#include<iostream>
#include<cstring>
using namespace std;

const int NMAX = 55;
int dp[NMAX][NMAX] = {};

void clearDP()								// 清零dp数组
{
	int i;
	for (i=0; i<NMAX; i++)
	{
		memset(dp[i], 0, sizeof(dp[i]));
	}
	return;
}

int max_odd(int i)							//返回小于等于i的最大正奇数
{
	if (i%2==1)
	{
		return i;
	}
	else
	{
		return (i-1);
	}
}



int main()
{
	int n,k,i1,i2,i3,ans2,ans3;
	while (cin >> n >> k)
	{
		if (n==1)
		{
			cout << 1 << endl << 1 << endl << 1 << endl;
			continue;
		}

		ans2 = 0;
		ans3 = 0;
		// 1. k个正整数和
		clearDP();
		dp[1][1] = 1;
		for (i1=2; i1<=n; i1++)
		{
			for (i2=1; i2<=k; i2++)
			{
				if (i2<=i1)
				{
					dp[i1][i2] = dp[i1-i2][i2] + dp[i1-1][i2-1];
				}
			}
		}
		cout << dp[n][k] << endl;
		// 2. 不同的正整数和
		clearDP();
		dp[1][1] = 1;
		for (i1 = 2; i1 <= n; i1++)
		{
			for (i2 = 2; i2<i1; i2++)
			{
				for (i3 = 1; i3 < i2; i3++)
				{
					dp[i1][i2] += dp[i1-i2][i3];
				}
			}
			dp[i1][i1] = 1;
		}
		for (i1=1; i1<=n; i1++)
		{
			ans2 += dp[n][i1];
		}
		cout << ans2 << endl;
		// 3. 正奇数和
		clearDP();
		dp[1][1] = 1;
		for (i1=2; i1<=n; i1++)
		{
			for (i2=1; i2<=max_odd(i1); i2=i2+2)
			{
				for (i3=1; i3<=i2; i3=i3+2)
				{
					dp[i1][i2] += dp[i1-i2][i3];
				}
			}
			if (i1==max_odd(i1))
			{
				dp[i1][i1] = 1;
			}
		}
		for (i1=0; i1<=n; i1++)
		{
			ans3 += dp[n][i1];
		}
		cout << ans3 << endl;
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/80684554
2.7