题目传送门 http://poj.org/problem?id=1664
设$dp[i][j]$表示$i$个苹果放在$j$个盘子里的总数
$1.$ 当 苹果数 小于 盘子数 $(M < N)$的时候,剩下的$N-M$个盘子都为空,问题等价于在$M$个盘子里放苹果:$$dp[M][N]=dp[M][M]$$
$2.$ 当苹果数 大于等于盘子数$(M \geq N)$的时候,其可以分解为全部盘子都至少放一个苹果$(dp[M-N][N])$和至少有一个盘子为空$(dp[M][N-1])$的两个子结果的合并: $$dp[M][N]=dp[M-N][N] + dp[M][N-1]$$
$3.$递归出口:
$dp[M][1] = 1 ;\\ dp[0][N] = 1$
注意这里,为什么不采用$M=1$呢?只剩一个果子,也是只有一种放法啊。但是,例如,若$dp[3][3] = dp[3][2] + dp[0][3]$,此时$M$为$0$,未收敛于出口$M=1$处,找不到数据。
/********************************* Author: jusonalien Email : [email protected] school: South China Normal University Origin: POJ *********************************/ #include <iostream> #include <cstdio> #include <map> #include <cstring> #include <string> #include <set> #include <queue> using namespace std; int dp(int m,int n) { //递归版本 if(m==0||n==1) return 1; if(m < n) return dp(m,m); else return (dp(m-n,n) + dp(m,n-1)); } int DP[15][15]; void solve() { //递推版本 for(int i = 0;i <= 12;++i) DP[0][i] = 1; for(int i = 0;i <= 12;++i) DP[i][1] = 1; for(int i = 1;i <= 10;++i) { for(int j = 1;j <= 10;++j) { if(i < j) DP[i][j] = DP[i][i]; else DP[i][j] = DP[i-j][j] + DP[i][j-1]; } } } int main(){ int m,n,t; solve(); scanf("%d",&t); while(t--) { scanf("%d%d",&m,&n); printf("%d\n",DP[m][n]); // printf("%d\n",dp(m,n)); } return 0; }
时间: 2024-11-10 07:28:58