Brush the 42-m liter of water into n cups (dynamic programming)

Original title link

Title description

要把m升的水倒入n个相同的容器中(假设容器足够大),允许有的容量是空的,
问共有多少种不同的倒法?5,1,1和1,5,1和1,1,5是同一种倒法。

Example

输入:
7 3
输出:
8

Reference analysis

1. 不妨设 f(m,n)为 把m升水倒入n个容器的总的方法数。
2. m>=n 可以分为两种情况,一种是n个容器内都一定有水,一种是n个容器内至少有一个没有水,这两种情况完全独立。
对于第一种,我们先将m中分出n升水,依次倒入每个桶,这样每个桶都一定有水,那么接下来的水的分配就是f(m-n,n)。
对于第二种的想法,就是先丢掉一个桶,这个桶一定没水,然后将m升水分配给余下的n-1个桶里(每个桶也不一定有水)。
所以有dp[ i ][ j ]  = dp[ i ][ j -1 ] + dp[ i - j ][ j ] 。
3. 下面是m<n的情况,也就是水少桶多,那么桶太多必定有部分桶未装水的情况。所以不妨直接扔掉(n-m)个桶,
然后就变成了n升水分配给n个桶的情况,即 dp[i][j] = dp[i][j-1];
4. 接下来初始化边值条件:dp[ 0 ][ i ] = 1, dp[ j ][ 0 ] = 1.在我的代码中,索引下标和水量,以及桶数都是一一对应的。

Reference Code

public static int solve(int m, int n) {
    
    
    // dp[i][j]表示将i升水导入j个瓶子的方法数
    int dp[][] = new int[m+1][n+1];
    // 边界情况dp[0][i] = 1, dp[j][0] = 1
    for (int i = 0; i < m+1; i++) {
    
    
        Arrays.fill(dp[i], 1);
    }
    for (int i = 2; i < m+1; i++) {
    
    
        for (int j = 2; j < n+1; j++) {
    
    
            // 水比桶多
            if (i >= j)
                // 分两种情况,(1)至少有一个桶没有水;(2)每个水桶都有水;
                dp[i][j] = dp[i][j - 1] + dp[i - j][j];
            // 桶比水多
            else
                dp[i][j] = dp[i][j - 1];
        }
    }
    return dp[m][n];
}

Guess you like

Origin blog.csdn.net/Awt_FuDongLai/article/details/111285500