C++ 动态规划 完全背包问题

C++ 动态规划 完全背包问题_第1张图片
这里先给出朴素做法,但是会TLE。因为这里时间复杂度最坏是N的三次方,也就是1e9比较慢,下面再给出优化的代码,

#include 
#include 

using namespace std;

const int N = 1010;
int n, m;
int v[N], w[N];
int f[N][N];

int main ()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++ )
        scanf("%d%d", &v[i], &w[i]);
        
    for(int i = 1; i <= n; i ++ )
        for(int j = 0; j <= m; j ++ )
            for(int k = 0; k * v[i] <= j; k ++ )
                f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);

    
    cout<<f[n][m]<<endl;
    
    return 0;
}

C++ 动态规划 完全背包问题_第2张图片
这是对完全背包问题的朴素解法的优化版本,主要是通过状态转移方程的优化来提高效率。

朴素版本中的状态转移方程为:

f[i][j]=max(f[i−1][j],max0≤k≤j/v[i]{f[i−1][j−k⋅v[i]]+k⋅w[i]})

在优化版本中,我们对状态转移方程进行改写,通过观察可知:

max0≤k≤j/v[i]{f[i−1][j−k⋅v[i]]+k⋅w[i]}

可以分解为两部分:

max0≤k≤j/v[i]{f[i−1][j−k⋅v[i]]}: 这部分与 jj 无关,只与 ii 和 v[i]v[i] 有关;
max⁡0≤k≤j/v[i]{k⋅w[i]}max0≤k≤j/v[i]{k⋅w[i]}: 这部分与 jj 直接相关,与 ii 和 v[i]v[i] 无关。

因此,我们可以将上述两部分分开考虑。首先,将第一部分提到循环外:

temp=max0≤k≤j/v[i]{f[i−1][j−k⋅v[i]]}

然后在内层循环中直接计算第二部分:

f[i][j]=max(f[i−1][j],temp+k⋅w[i])

这样,通过优化,将原来的二重循环变为了单重循环,提高了效率。最终的状态转移方程为:

f[i][j]=max⁡(f[i−1][j],f[i][j−v[i]]+w[i])f[i][j]=max(f[i−1][j],f[i][j−v[i]]+w[i])

这样的优化在完全背包问题中非常常见,能够有效提高程序运行速度。

#include 
#include 

using namespace std;

const int N = 1010;
int n, m;
int v[N], w[N];
int f[N][N];

int main ()
{
    cin>>n>>m;
    for(int i = 1; i <= n; i ++ )
        cin>>v[i]>>w[i];
        
    for(int i = 1; i <= n; i ++ )
        for(int j = 0; j <= m; j ++ )
        {
            f[i][j] = f[i - 1][j];
            if(j >= v[i])
                f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);
        }

    
    cout<<f[n][m]<<endl;
    
    return 0;
}

你可能感兴趣的:(动态规划,算法笔记,力扣,c++,动态规划)