ybt1192放苹果后续:正解

ybt1192放苹果

注:本篇为此篇后续

真正的正解

找规律

上次的想法只是一时灵机一动,但小聪明是不能解决问题的,所以要理性地分析,在复杂的问题,经过分解都会变得简单。

盘子\苹果 1 2 3 4 5
1 1 1 1 1 1
2 1 2 2 3 3
3 1 2 3 4 5
4 1 2 3 5 6
5 1 2 3 5 7

设i果j盘的方案数是f~i,j~

在列表后可以发现,表格的第一行和第一列都是1,并且易知m或n为零时的方案数,这便是我们递推的边界条件。

写出初始化代码:

f[0][0]=1;
for(int i=1;i<=10;i++) {
    f[1][i]=1;
    f[i][1]=1;
    f[0][i]=1;
    f[i][0]=0;
}

另外,在盘子比苹果多的时候,方案数不再随盘子的增多而增多。

所以当i<j时,f~i,j~=f~i,i~

要想进行递推,找清状态关系是关键,在列上文的表时,我是先将所有苹果放在第一个盘子里,然后一个一个往后拿,直到在保证苹果数量递减的前提下无法往后拿为止。一开始就会出现在后面的盘子里大量出现零的情况,那么我们就可以这样分类。

\[ 总方案=有空盘方案+无空盘方案 \]

当有空盘时​,至少但不仅仅有一个盘子没放苹果,所以这时的问题就简化成j-1个盘子放i个苹果的情况;

当没有空盘时,每个盘子有至少但不仅仅一个苹果,所以这时将每个盘子的第一个苹果去掉,问题就简化成将i-j个苹果放进j个盘子的情况。

写出方程: f~i,j~=f~i,j-1~+f~i-j,j~

/*完整代码*/
#include<iostream>
using namespace std;
int f[15][15],t,m,n;
int main() {
    f[0][0]=1;
    for(int i=1;i<=10;i++) {
        f[1][i]=1;
        f[i][1]=1;
        f[0][i]=1;
        f[i][0]=0;
    }
    for(int j=2; j<=10; j++) {//枚举盘子数
        for(int i=2;i<=j;i++){//苹果比盘子少 
            f[i][j]=f[i][i]; 
        }
        for(int i=j; i<=10; i++) {//枚举苹果数 
            f[i][j]=f[i][j-1]+f[i-j][j];
            //cout<<i<<"    "<<j<<" "<<f[i][j]<<endl; //测试,重要,勿动!!!
        }
    }
    cin>>t;
    for(int k=1;k<=t;k++) {
        cin>>m>>n;
        cout<<f[m][n]<<endl;
    }
    return 0;
}

思路来自这里,感谢

猜你喜欢

转载自www.cnblogs.com/Wild-Donkey/p/12213237.html
今日推荐