openjudge_2.5基本算法之搜索_666:放苹果

题目

666:放苹果
总时间限制: 1000ms 内存限制: 65536kB
描述
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
输入
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
输出
对输入的每组数据M和N,用一行输出相应的K。
样例输入
1
7 3
样例输出
8

理解

如果i个苹果不一样,j个盘子一样,就用插空法解决。
i个苹果中间有i+1个空隙,这些空隙里挑j个,组合问题c(i+1,j)。
现在苹果一样,盘子一样,也是组合问题,
分类成两种情况,盘子全满了和有空盘子两种,分类就是加法。
f[i][j]=f[i][j-1]+f[i-j][j]
f[7][3]=f[7][2]+f[4][3]
7个苹果分3个盘子
7 0 0
6 1 0
5 2 0
5 1 1
4 3 0
4 2 1
3 3 1
转换成较小的两种状态,所有盘都有和个别盘空
7 0 0
6 1 0
5 2 0
4 3 0
5 1 1
4 2 1
3 3 1
个别盘空,就是问题转换成7个苹果2个盘
7 0 0
6 1 0
5 2 0
4 3 0
所有盘都满
5 1 1
4 2 1
3 3 1
每个盘都减去要给苹果,组合数不变
4 0 0
3 1 0
2 2 0
刚好就是7-3=4个苹果2个盘的状态
如果苹果比盘子少,多的盘子没用
f[i][j]=f[i][j-1]
总之就是用分类原理,把大规模问题转换成相对小规模问题,直到最初有答案的问题。递归也可以,动规也可以

动规

#include <bits/stdc++.h>
using namespace std;
int t,//几组数据
a,//几个苹果
p,//几个盘子
f[11][11];
/*
几个同苹果分到几个同盘子的分发
如果苹果够分的话
f[i][j]=f[i][j-1]+f[i-j][j]
f[7][3]=f[7][2]+f[4][3]
*/
void view(){
cout<<“盘子\t”; for(int j=0;j<=p;j++)cout<<j<<“\t”;cout<<endl;
for(int i=0;i<=a;i++){
cout<<i<<“苹果\t”;
for(int j=0;j<=p;j++)cout<<f[i][j]<<“\t”;cout<<endl;
}
}
int main(){
//freopen(“data.cpp”,“r”,stdin);
cin>>t;
while(t–){
memset(f,0,sizeof(f));
cin>>a>>p;
for(int i=0;i<=p;i++)f[0][i]=1;//不管有几个盘子,0个苹果都只能分一种
for(int i=0;i<=p;i++)f[i][1]=1;//不管有几个苹果,1个盘子也都只能分一种
for(int i=1;i<=a;i++)
for(int j=1;j<=p;j++)
//如果苹果够分,可以拆分成类求和,一个是盘子都满了,一个有空盘子
if(i>=j)f[i][j]=f[i][j-1]+f[i-j][j];
//如果苹果不够分,那多余的盘子没用
else f[i][j]=f[i][j-1];
//view();
cout<<f[a][p]<<endl;
}
return 0;
}

递归

#include <bits/stdc++.h>
using namespace std;
int t,//几组数据
a,p;
int go(int a,int p){
if(a= =0||a= =1||p==1)return 1;//递归出口,没有苹果或者只有1个苹果或者只有一个盘子,只有一种分发
if(a<p)return go(a,a);
else return go(a,p-1)+go(a-p,p);
}
int main(){
//freopen(“data.cpp”,“r”,stdin);
cin>>t;
while(t–){
cin>>a>>p;
cout<<go(a,p)<<endl;
}
return 0;
}

小结

只要找到动态转移方程,
用递归和动规无所谓。
动态转移方程,还是得分析数据,才能归纳出规律。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值