划分数

划分数  挑战上的题

***************************************************************************************

注意是不超过

1、定义dp[i][j]=j的i的划分总数  j的i划分表示的意义为 j固定,i可以取到1-i。

2、递推公式  dp[i][j]=dp[i][j-i]+dp[i-1][j];

3、分类讨论:

      1.j >= i时,dp[i][j] = dp[i-1][j] ( j的i-1划分,相当于当前位取0的全部情况 ) + dp[i][j-i](当前位不取0,先把每一个置为1,再将剩下的j-i分下去);

      2.j < i时,dp[i][j] = dp[i-1][j];  当前位只能取0。

例题:

郭姐最近很无聊,于是就开始分石头。郭姐有n颗石头,她要把石头分成m堆,每堆至少有一个石子,她想知道有多少种分法

输入描述

  • 2个整数,n和m(m <= n <= 20)。

输出描述

  • 一个整数,表示种数

样例输入  7 3  样例输出  4

来源   2016年中北大学新生赛

提示   由于石头都是一样的,若仅仅只是顺序不同,那还是同一种分法,比如把7分成3堆,(1,1,5)和(1,5,1)是同一种

注意是刚好m堆,每堆至少一个石子

上述提到的公式是适用于不超过m即空堆是小于m的数即可 所以注意最后答案是(看代码)

#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
int dp[50][50];
int main(){
	int n,m;
	cin>>n>>m;
	dp[0][0]=1;
	for(int i=1;i<=m;i++){
		for(int j=0;j<=n;j++){
			if(j>=i){
				dp[i][j]=dp[i][j-i]+dp[i-1][j];
			}else
			dp[i][j]=dp[i-1][j];
		}
	}
	int ans=dp[m][n]-dp[m-1][n];//注意
	cout<<ans<<endl;
    return 0;
} 

牛客  放苹果   一样的题https://www.nowcoder.com/questionTerminal/bfd8234bb5e84be0b493656e390bdebf

不过是不超过M堆的情况;

#include<algorithm>
#include<iostream>
#include<stdlib.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
int dp[50][50];
int main(){
	int n,m;
	cin>>m>>n;
	dp[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			if(j>=i)
			  dp[i][j]=dp[i][j-i]+dp[i-1][j];
			else
			  dp[i][j]=dp[i-1][j];  
		}
	}
	int ans=dp[n][m];
	cout<<ans<<endl;
	return 0;
}

递归也可以写

牛客该题下讨论有详解,感兴趣可以去学一下

猜你喜欢

转载自blog.csdn.net/gml1999/article/details/84445705
今日推荐