整数划分问题(完全背包)(总方案数和最小方案数)

发布时间 2023-08-15 19:15:47作者: 彦辰kkkkk

完全背包解决整数划分问题:

总方案数:

完全背包:在前i个数中选,且总和恰好等于j的方案数
f[i][j] = f[i - 1][j] + f[i - 1][j - v]

化成一维:

f[j] += f[j - v];

这种求总方案数的情况需要把f初始化为0,然后f[0]初始化为1,最后累加f[j]

900. 整数划分

这里从小到大枚举i,用到的v就是枚举的i

#include <bits/stdc++.h>

using namespace std;

const int N = 1010, mod = 1e9 + 7;

int n;
int f[N];

int main()
{
    cin >> n;
    f[0] = 1;
    for(int i = 1; i <= n; i ++ )
        for(int j = i; j <= n; j ++ )
            f[j] = (f[j] + f[j - i]) % mod;

    cout << f[n] << endl;

    return 0;
}

最小方案数:

在前i个数中选,最后总和为j需要最少多少个数

一维:f[j] = min(f[j], f[j - v] + 1)

解释:总和为j时不选第i个数,总和为j时选第i个数(选第i个数前是f[j - v],选完第i个数后答案需要 + 1,代表选了1个第i个数),两者取最小值。

最小方案这种情况需要把f初始化为0x3f,f[0]初始化为0

279. 完全平方数

class Solution {
int f[10010];
public:
    int numSquares(int n) {
        memset(f, 0x3f, sizeof f);
        f[0] = 0;
        for(int i = 1; i <= n / i; i ++ )
        {
            int v = i * i;
            for(int j = v; j <= n; j ++ )
                f[j] = min(f[j], f[j - v] + 1);
        }
        return f[n];
    }
};

322. 零钱兑换

class Solution {
int f[100010];
public:
    int coinChange(vector<int>& coins, int amount) {
        memset(f, 0x3f, sizeof f);
        f[0] = 0;
        int n = coins.size();
        for(int i = 0; i < n; i ++ )
        {
            int v = coins[i];
            for(int j = v; j <= amount; j ++ )
                f[j] = min(f[j], f[j - v] + 1);
        }
        if(f[amount] == 0x3f3f3f3f) return -1;
        return f[amount];
    }
};