多元一次不定方程解的个数

#!/usr/bin/python3.6
# -*- coding: utf-8 -*-

"""
多元一次不定方程解的个数

problem1: 将30条鱼放入10个桶中, 每个桶至少一条鱼, 总共有多少种方法?
本质:
    x1 + x2 + x3 + x4 + ... + xi = n, xi > 0, n > i
    本题:  x1 + x2 + x3 + x4 + ... + x9 + x10 = 30, x1~x10 > 0

解答: 隔板法, 每条鱼可以视为数值1, 插入板子后将1相加
            n条鱼排一列, 板子能放的位置是 = n - 1
            要i个数, 需要插入 i - 1个板子
            所求即为板子的位置, so答案为排列组合, C(n - 1, i - 1), 板子顺序没关系

     扩展1: 当xi >= 0时
        x1 + x2 + ... + xi = n的非负整数解个数与 y1 + y2 + ... + yi = n + i (yi = xi+1, i=[1,r]) 的正整数解个数是相同的
        所以答案为 C(n + i - 1, i - 1)
     扩展2: x1 >= -2, x2... > 0
        x1 + x2 + ... + xi = n的整数解个数与 y1 = x1 + 3, y1 + x2 + ... + xi = n + 3的正整数解的个数
        所以答案为C(n + 3 - 1, i - 1)

problem2: 将30条鱼放入10个桶中, 每个桶可以放0-10条, 总共有多少种方法?
本质:
    x1 + x2 + x3 + x4 + ... + xi = n, 0 <= xi <= 10
    本题:  x1 + x2 + x3 + x4 + ... + x9 + x10 = 30, 0 <= x1~x10 <= 10

"""


class Problem2(object):
    @classmethod
    def solution1(cls, box, fish, max_fish_num: int = 10):
        """ 递归 """
        if fish < 0 or box < 0 or (box < 1 and fish > 0):
            return 0
        if box == 0 and fish == 0:
            return 1
        if box == 1:
            return int(fish <= max_fish_num)
        ans = 0
        for i in range(0, max_fish_num + 1):
            ans += cls.solution1(box - 1, fish - i, max_fish_num=max_fish_num)
        return ans

    @classmethod
    def solution2(cls, box, fish, max_fish_num: int = 10):
        """ 动态规划 """
        if fish < 0 or box < 0 or (box < 1 and fish > 0):
            return 0
        if box == 0 and fish == 0:
            return 1
        if box == 1:
            return int(fish <= max_fish_num)

        # row = fish, col = box
        box += 1  # 盒子和球的个数都为0的时候
        dp = [[0] * box for _ in range(fish + 1)]
        dp[0] = [1] * box
        for i in range(1, fish + 1):  # row 鱼的数量
            for j in range(1, box):   # col 桶的数量
                tmp = 0
                for m in range(0, max_fish_num + 1):
                    if i - m < 0:
                        break
                    # 少的那个桶放0~max_fish_num个鱼
                    tmp += dp[i - m][j - 1]
                # end for
                dp[i][j] = tmp
            # end for
        # end for

        return dp[-1][-1]

    @staticmethod
    def help(m, n):
        ans = 1
        for i in range(m, m - n, -1):
            ans *= i
        for i in range(1, n + 1):
            ans /= i
        return ans


if __name__ == '__main__':
    for a, b in [[5, 15], [4, 18], [5, 30]]:
        print(a, b, "=>", Problem2.solution1(a, b), Problem2.solution2(a, b))

你可能感兴趣的:(算法,面试题,数据结构和算法)