读书笔记 ---- 0

/**
0-1 背包问题:经典动态规划入门题
记忆化搜索方法:静态记录下递归过程中的状态值,避免重复计算

在 n 个重量和价值分别是 wi 和 vi 的物品中挑选,使得物品重量总和
不超过 W, 并且让其价值总和尽量大

问题规模:
1 <= n <= 100
1 <= wi,vi <= 100
1 <= W <= 10000
状态转移方程:
dp(i,S) = dp(i - 1, S - w[i]) + v[i]; // S - w[i] >= 0
*/

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXW = 10000 + 5;
const int N = 100 + 5;
int n,W;
int w[N],v[N];
int d[N][MAXW];

int dp(int i, int S)
{
    int &ans = d[i][S];
    if(ans != -1) return ans;
    ans = 0;
    if(i == 0)
        return ans;
    if(S - w[i] >= 0)
        ans =max(dp(i - 1, S), dp(i - 1, S - w[i]) + v[i]);
    else
        ans =dp(i-1, S);
    return ans;
}
void solve()
{
    scanf("%d%d", &n, &W);
    for(int i = 1; i <= n ; i++)
        scanf("%d", w[i]);
    for(int i = 1; i <= n; i++)
        scanf("%d", v[i]);
    memset(d, -1, sizeof(d));
    dp(n, W);
}
int main()
{
    solve();
    return 0;
}
/**
0-1 背包问题:经典动态规划入门题

在 n 个重量和价值分别是 wi 和 vi 的物品中挑选,使得物品重量总和
不超过 W, 并且让其价值总和尽量大

问题规模:
1 <= n <= 100
1 <= wi,vi <= 100
1 <= W <= 10000
状态转移方程:
dp[i][j] = dp[i-1][j-w[i]] + v[i]; // j - w[i] >= 0
*/

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXW = 10000 + 5;
const int N = 100 + 5;
int n,W;
int w[N],v[N];
int dp[N][MAXW];

void solve()
{
    scanf("%d", &n, &W);
    for(int i = 1; i <= n ; i++)
        scanf("%d", w[i]);
    for(int i = 1; i <= n; i++)
        scanf("%d", v[i]);
    memset(d, 0, sizeof(d));
    for(int i = 1; i <= n; i++)
    {
        for(int j = 0; j <= W; j++)
        {
            if(j < w[i])
                dp[i][j] = dp[i-1][j];
            else
                dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i]] +v[i]);
        }
    }
    printf("%d
", dp[n][W]);
}
int main()
{
    solve();
    return 0;
}
/**
在 n 种重量和价值分别是 wi 和 vi 的物品中挑选,使得物品重量总和
不超过 W, 并且让其价值总和尽量大

问题规模:
1 <= n <= 100
1 <= wi,vi <= 100
1 <= W <= 10000

0-1背包:每种物品只有一个
状态转移方程:dp[i][j] = max(dp[i-1][j] ,dp[i-1][j-w[i]]+v[i]);
0-1背包的状态更新只跟上一层的考虑有关系

完全背包:每种物品有无数个
状态转移方程:dp[i][j] = max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
完全背包在本层中,需要考虑 对选择过本层物品后更新的状态 的使用,
所以在实现上有所差别
*/

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXW = 10000 + 5;
const int N = 100 + 5;
int n,W;
int w[N],v[N];
int dp[MAXW];
/**
都使用一维数组来写
*/
void solve_01()
{
    scanf("%d", &n, &W);
    for(int i = 1; i <= n ; i++)
        scanf("%d", w[i]);
    for(int i = 1; i <= n; i++)
        scanf("%d", v[i]);
    memset(d, 0, sizeof(d));
    for(int i = 1; i <= n; i++)
    {
        for(int j = W; j >= 0; j--)
        {
            //这里使用的数据都是没有更新过的上层数据
            if(j >= w[i])
                dp[j] = max(dp[j], dp[j - w[i]] +v[i]);
        }
    }
    printf("%d
", dp[n][W]);
}

void solve_entire()
{
    scanf("%d", &n, &W);
    for(int i = 1; i <= n ; i++)
        scanf("%d", w[i]);
    for(int i = 1; i <= n; i++)
        scanf("%d", v[i]);
    memset(d, 0, sizeof(d));
    for(int i = 1; i <= n; i++)
    {
        for(int j = 0; j <= W; j++)
        {
            //这里使用的数据都是有更新过的上层数据
            if(j >= w[i])
                dp[j] = max(dp[j], dp[j - w[i]] +v[i]);
        }
    }
    printf("%d
", dp[n][W]);
}
int main()
{
    solve_01();
    return 0;
}
/**
在 n 个重量和价值分别是 wi 和 vi 的物品中挑选,使得物品重量总和
不超过 W, 并且让其价值总和尽量大

问题规模:
1 <= n <= 100
1 <= vi <= 100
1 <= wi <= 1e7
1 <= W <= 1e9

这题的重量的数量级比普通的背包扩大了10000倍,所以再使用之前的算法
枚举重量状态O(n*W),次数量到达1e11,这将不是1s可以跑出来的方法。

所以改变策略,状态描述为dp[i][j],考虑前i个物品价值总和为j的最小重量,
状态转移方程:
dp[i][j] = min(dp[i-1][j], dp[i-1][j-v[i]]+w[i]);
然后从所有的价值状态中,找到重量合法的最大价值
*/

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXW = 1e9 + 5;
const int MAXV = 1e5 + 5;
const int N = 100 + 5;
int n,W;
int w[N],v[N];
int dp[N][MAXV];

void solve_entire()
{
    int maxv = 0;
    scanf("%d", &n, &W);
    for(int i = 1; i <= n ; i++)
        scanf("%d", w[i]);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", v[i]);
        maxv += v[i];
    }
    memset(d, 0x3f, sizeof(d));

    for(int i = 1; i <= n; i++)
    {
        for(int j = 0; j <= maxv; j++)
        {
            if(j < v[i])
                dp[i][j] = dp[i-1][j];
            else
                dp[i][j] = min(dp[i-1][j], dp[i-1][j-v[i]]+w[i]);
        }
    }
    int ans = maxv;
    for(int i = maxv; i >= 0; i--)
    {
        if(dp[n][j] <= W)
        {
            ans = j;
            break;
        }
    }
    printf("%d
", ans);
}
int main()
{
    solve();
    return 0;
}



如果有错误,请指出,谢谢
原文地址:https://www.cnblogs.com/Alruddy/p/7163197.html