[dp]poj1664 放苹果 dp解法

来源:互联网 发布:php 商城好评怎么写 编辑:程序博客网 时间:2024/05/21 22:30


放苹果
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 27747 Accepted: 17550

Description

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

Input

第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。

Output

对输入的每组数据M和N,用一行输出相应的K。

Sample Input

17 3

Sample Output

8

这道题目除了用dp做以外,还可以用很多其他的方法过。因为题目数据非常小,各路大牛的博客上有层出不穷的解法,我见过的有可以用DFS递归的方法,组合数学的方法,还有暴力打表法……今天来探讨一下使用dp做的方法。


拿到题目一看,很容易想到用dp[i][j] 表示共i个苹果放入j个盘子的方法。

状态转移的过程一看好像很多。不知如何构建,但是我们可以从目标状态入手!把i个苹果放入j个盘子里的情况无非有两种

1、这j个盘子中有空盘子,这时候i个苹果放入j个盘子的方法和i个苹果放入j-1个盘子的方法是一样的,

得到dp[i][j] = dp[i][j-1] (当满足i<j时,此情况必定成立。)

2、 j个盘子中没有空盘子,那么我们可以从每个盘子中移除一个,那么原问题转换成把i-j个苹果放到j个盘子里。


题目里面很难理解的一点是,为什么没有空盘子时,苹果只拿走一个?

这个问题我们可以这样想,假设放置最少的盘子中有k个苹果,那么这个状态可以唯一地,由连续k次每次从每个盘子中拿走一个苹果而得到,所以就不会出现重复的子状态,也就满足了题目的显示条件!

想清楚以后,还有边界条件需要非常注意,dp[0][i] = 1,dp[1][i] = 1,dp[i][1] = 1;

#include <cstdio>#include <iostream>#include <cstring>using namespace std;const int MAXN = 15;int dp[MAXN][MAXN];int M,N;// 定义dp[i][j]为把i个苹果放在j个盘子里的放法//     dp[i][j] = dp[i][j-1] 或者//     dp[i][j] = dp[i][j-1] +dp[i-j][j]////     如果j个盘子中有空盘子,那么就转换成dp[i][j-1]//     如果没有空盘子,我们就先给这j个盘子放每个盘子放一个苹果//     转换成dp[i-j][j]//int main(){    int T;    cin>>T;    while(cin>>M>>N)    {        memset(dp,-1,sizeof(dp));        for(int i = 1; i<=10; i++)            dp[0][i] = dp[1][i] = dp[i][1] = 1;        for(int i = 1; i <= 10; i++)        {            for (int j =1; j<=10; j++)            {                if(dp[i][j] == -1)                {                    if (i<j) //证明有空盘子                        dp[i][j] = dp[i][j-1];                    else  //证明没有空盘子,那就先给这j个盘子里面每个                        //都放一个苹果,转换成dp[i-j][j];                        dp[i][j] = dp[i][j-1] +dp[i-j][j];                }            }        }        cout<<dp[M][N]<<endl;    }}


0 0
原创粉丝点击