整数的划分-数的划分-放苹果

洛谷P1025数的划分

洛谷P2386放苹果

整数的划分是一类DP的经典题,也可用递归解决。

数的划分:将整数ン分成KK份,且每份不能为空,任意两个方案不相同(不考虑顺序)。

DFS版本:

#include<bits/stdc++.h>
#define maxn 100000+5
#define INF 0x3f3f3f3f
#define for1(i,l,r) for(int i=l;i<=r;++i)
#define for2(i,l,r) for(int i=l;i>=r;--i)
#define mst(a) memset(a,0,sizeof a)
#define ll long long
using namespace std;
//题号:P1025 数的划分
//问题:将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
//解法:dfs 
/*总结:
*/
int n,k,sum = 0;
void f(int num,int t,int j)//num表示总数,t表示划分的个数 j 表示当前划分最大值 
{//按照递增的划分因此要记录 上一次划分的最大值 j
	if(t==k)
	{
		if(num==n)
			sum++;
		return; 
	} 
	for(int i = j;i<=n;i++)
	{
		if(num+i*(k-t)>n) return;
		if(num+i<=n)f(num+i,t+1,i);
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>k;
	f(0,0,1);
	cout<<sum<<endl;
	return 0;
}

DP版本:

#include<bits/stdc++.h>
#define maxn 100000+5
#define INF 0x3f3f3f3f
#define for1(i,l,r) for(int i=l;i<=r;++i)
#define for2(i,l,r) for(int i=l;i>=r;--i)
#define mst(a) memset(a,0,sizeof a)
#define ll long long
using namespace std;
//题号:数的划分Dp 
//问题:将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
//解法:dp 整数的划分 
/*总结:
*/
int f[205][15];
int main()
{
	ios::sync_with_stdio(false);
	int n,m;
	cin>>n>>m;
	for(int i = 1;i<=n;i++)f[i][1] = 1;
	for(int i = 1;i<=n;i++)
		for(int j = 2;j<=m;j++)//从1开始会把初始化给盖掉 
		{
			if(i>=j)f[i][j] = f[i-1][j-1]+f[i-j][j];
		} 
	cout<<f[n][m]<<endl;
	return 0;
}

放苹果DP + DFS:

#include<bits/stdc++.h>
#define maxn 100000+5
#define INF 0x3f3f3f3f
#define for1(i,l,r) for(int i=l;i<=r;++i)
#define for2(i,l,r) for(int i=l;i>=r;--i)
#define mst(a) memset(a,0,sizeof a)
#define ll long long
using namespace std;
//题号:放苹果
//问题:把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
//解法:递推 递归 
/*总结:
f(m, n)表示将m个苹果放入n个盘子 
f(10,3) = f(10, 2) + f(7, 3) 
10个苹果放入3个盘子 = 10个苹果放入2个盘子(有空盘子,有一个盘子不放)
+ 7个苹果放入3个盘子(没有空盘子,每一个盘子里面先各放一个苹果,就只剩下7个苹果)
*/
int A[15][15];
int main()
{
	ios::sync_with_stdio(false);
	
	for1(i,0,10)//果 
		for1(j,1,10)//盘子 
		{
			if(i==0||j==1)
			{
				A[i][j] = 1;
				continue;
			}
			A[i][j] = A[i][j-1];
			if(i>=j)A[i][j]+=A[i-j][j];
		}
	int n;
	cin>>n;
	for1(i,1,n)
	{
		int a,b;
		cin>>a>>b;
		cout<<A[a][b]<<endl;
	}
	return 0;
}
//dfs
int dfs(int m,int n){   
    if(m==0||n==1)    
        return 1;     
    if(n>m)  
        return dfs(m,m);  //如果前面的小于后面的,则一定会有空盘子,则等于m个苹果放入m个盘子 
    else  
        return dfs(m,n-1)+dfs(m-n,n);  //有空盘子的情况 + 没有空盘子的情况 
} 

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

下面内容转自:HTTPS://blog.csdn.net/Athenaer/article/details/8265234 

常见的有以下3种:
1。将n划分成不大于m的划分法: 

2.将Ñ划分成ķ个数的划分法:

3.将ñ划分成若干奇数的划分法:


1.将Ñ划分成不大于米的划分法: 

   1)若是划分多个整数可以存在相同的:

    dp [n] [m] = dp [n] [m-1] + dp [nm] [m] dp [n] [m]表示整数n的划分中,每个数不大于m的划分数。
       则划分数可以分为两种情况:
       a。划分中每个数都小于m,相当于每个数不大于m-1,故划分数为dp [n] [m-1]。
       b。划分中有一个数为m。那就在n中减去m,剩下的就相当于把nm进行划分,故划分数为dp [nm] [m];

  2)若是划分多个不同的整数。:

  dp [n] [m] = dp [n] [m-1] + dp [nm] [m-1] dp [n] [m]表示整数n的划分中,每个数不大于m的划分数。
      同样划分情况分为两种情况:
      a。划分中每个数都小于m,相当于每个数不大于m-1,划分数为dp [n] [m-1]。
      b。划分中有一个数为m。在n中减去m,剩下相当对nm进行划分,

   并且每一个数不大于m-1,故划分数为dp [nm] [m-1]

2.将Ñ划分成ķ个数的划分法:

 dp [n] [k] = dp [nk] [k] + dp [n-1] [k-1];

     方法可以分为两类:
       第一类:N份中不包含1的分法,为保证每份都> = 2,可以先拿出ķ个1分
     到每一份,然后再把剩下的Ñ - K分成ķ份即可,分法有:DP [NK] [k]的
       第二类:N份中至少有一份为1的分法,可以先那出一个1作为单独的1份,剩
     下的n-1再分成k-1份即可,分法有:dp [n-1] [k-1]

   

3.将ñ划分成若干奇数的划分法:

    G [i] [j]:将我划分为Ĵ个偶数

    f [i] [j]:将我划分为j个奇数
     g [i] [j] = f [i - j] [j]; 
     f [i] [j] = f [i - 1] [j - 1] + g [i - j] [j];

 方法可以分为两类:

  第一类:ⅰ中拿出Ĵ个1分到每一份中,将剩余的IJ分成Ĵ个奇数

  第二类:一份包含奇数1,剩余的I-1分成J-1个奇数;另一种,每份至少大于1,将Ĵ个1拿出来分到每一份中,其余IJ分成Ĵ份

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值