01背包、完全背包、多重背包

参考(都有些错误):https://github.com/guanjunjian/Interview-Summary/blob/master/notes/algorithms/%E7%BB%8F%E5%85%B8%E7%AE%97%E6%B3%95/01%E8%83%8C%E5%8C%85.mdhttps://blog.csdn.net/na_beginning/article/details/62884939
#include <iostream>
#include <sstream>
#include <vector>
#include <string>

using namespace std;

/*
01背包问题 每个物品仅一个
状态转移公式:F[i][j] = F[i - 1][j] 和 F[i - 1][j - W[i]] + V[i] 大的那个值
C背包总重量
W每个物品重量
V每个物品价值
n物品总数
inp具有最大价值时,标记哪个物品在包中
返回最大价值
*/
int packages(int C, vector<int> &W, vector<int> &V, int n, vector<int> &inp)
{
    vector<vector<int> > F(n, vector<int>(C + 1));//F[i][j]记录背包可用重量为j时,前i个物品的最大价值

    for (int i = 0; i < n; i++)//初始化表格
    {
        for (int j = 0; j < F[0].size(); j++)
            F[i][j] = 0;
    }
    for (int j = 1; j < F[0].size(); j++)//初始化第一行
        F[0][j] = (j < W[0]) ? 0 : V[0];//可用重量j大于物品重量,则装入该物品,加上该物品价值

    for (int i = 1; i < n; i++)
    {
        for (int j = 1; j < F[0].size(); j++)
        {
            if (j < W[i])
                F[i][j] = F[i - 1][j];//装不下该物品
            else
                F[i][j] = (F[i - 1][j] < F[i - 1][j - W[i]] + V[i]) ? F[i - 1][j - W[i]] + V[i] : F[i - 1][j];//可装下该物品。状态转移方程
        }
    }
    int result = F[n - 1][F[0].size() - 1];//最大价值

    //inp标记哪些物品在包中
    int j = C;
    for (int i = n-1; i >0 ; i--)//i不可为0,否则F[i-1]越界
    {
        if (j>W[i] && F[i][j] == F[i - 1][j - W[i]] + V[i])//注意需要j>W[i]
        {
            inp[i] = 1;
            j -= W[i];
        }
    }
    if (F[0][j] > 0)//如果背包还可装下,则包含第一个物品
        inp[0] = 1;

    //输出动态规划数组
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < F[0].size(); j++)
            cout << F[i][j] << " ";
        cout << endl;
    }

    return result;
}

/*
01背包问题 滚动数组优化动态规划的空间
原空间OnC,先空间O2C,但是无法输出有哪些物品在包中
*/
int packages_good(int C, vector<int> &W, vector<int> &V, int n)
{
    vector<vector<int> > F(2, vector<int>(C + 1));//F[i][j]记录背包可用重量为j时,前i个物品的最大价值

    for (int i = 0; i < 2; i++)//初始化表格
    {
        for (int j = 0; j < F[0].size(); j++)
            F[i][j] = 0;
    }
    for (int j = 1; j < F[0].size(); j++)//初始化第一行
        F[0][j] = (j < W[0]) ? 0 : V[0];//可用重量j大于物品重量,则装入该物品,加上该物品价值

    int k = 0;
    for (int i = 1; i < n; i++)
    {
        k = i & 1;//滚动
        for (int j = 1; j < F[0].size(); j++)
        {
            if (j < W[i])
                F[k][j] = F[k ^ 1][j];//装不下该物品
            else
                F[k][j] = (F[k ^ 1][j] < F[k ^ 1][j - W[i]] + V[i]) ? F[k ^ 1][j - W[i]] + V[i] : F[k ^ 1][j];//可装下该物品
        }
    }
    return F[k][F[0].size() - 1];//最大价值
}

/*
完全背包 每个物品不限制数量
状态转移公式:F[i][j] = F[i - 1][j] 和 F[i][j - W[i]] + V[i] 大的那个值,标记哪些物品在包中也改变
注意是F[i][j - W[i]] + V[i]
也可优化空间
*/
int packages_full(int C, vector<int> &W, vector<int> &V, int n, vector<int> &inp)
{
    vector<vector<int> > F(n, vector<int>(C + 1));//F[i][j]记录背包可用重量为j时,前i个物品的最大价值

    for (int i = 0; i < n; i++)//初始化表格
    {
        for (int j = 0; j < F[0].size(); j++)
            F[i][j] = 0;
    }
    for (int j = 1; j < F[0].size(); j++)//初始化第一行
        F[0][j] = (j < W[0]) ? 0 : ((j/W[0])*V[0]);//每个物品不止一个

    for (int i = 1; i < n; i++)
    {
        for (int j = 1; j < F[0].size(); j++)
        {
            if (j < W[i])
                F[i][j] = F[i - 1][j];//装不下该物品
            else
                F[i][j] = (F[i - 1][j] < F[i][j - W[i]] + V[i]) ? F[i][j - W[i]] + V[i] : F[i - 1][j];//可装下该物品。状态转移方程
        }
    }
    int result = F[n - 1][F[0].size() - 1];//最大价值

    //inp标记哪些物品在包中
    int j = C;
    int i = n - 1;
    while (i)
    {
        while(j && j > W[i] && F[i][j] <= F[i][j - W[i]] + V[i]) //如果包含该物品,则一直循环看包含几个该物品
        {
            inp[i]++;
            j -= W[i];
        }
        i--;//不包含该物品,则跳到下一个物品
    }

    //输出动态规划数组
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < F[0].size(); j++)
            cout << F[i][j] << " ";
        cout << endl;
    }

    return result;
}

/*
多重背包 每个物品有数量限制
*/
int packages_multi(int C, vector<int> &W, vector<int> &V, int n, vector<int> &inp, vector<int> &N)//N会被修改
{
    vector<vector<int> > F(n, vector<int>(C + 1));//F[i][j]记录背包可用重量为j时,前i个物品的最大价值

    for (int i = 0; i < n; i++)//初始化表格
    {
        for (int j = 0; j < F[0].size(); j++)
            F[i][j] = 0;
    }
    for (int j = 1; j < F[0].size(); j++)//初始化第一行,每个物品有对应数量N限制
    {
        int count = (N[0] > j / W[0]) ? j / W[0] : N[0];//可用空间为j时,可以放多少个当前物品,min{可放入数量,物品数量}
        F[0][j] = (j < W[0]) ? 0 : (count*V[0]);
    }

    for (int i = 1; i < n; i++)
    {
        for (int j = 1; j < F[0].size(); j++)
        {
            if (j < W[i])
                F[i][j] = F[i - 1][j];//装不下该物品
            else
            {
                int count = (N[i] > j / W[i]) ? j / W[i] : N[i];
                F[i][j] = F[i - 1][j];//不放当前物品
                for (int k = 1; k <= count; k++)//看放入多少个当前物品可以让F[i][j]最大
                {
                    int tmp = F[i - 1][j - k * W[i]] + k * V[i];//放入k个当前物品
                    if (tmp > F[i][j])
                        F[i][j] = tmp;
                }
            }
        }
    }
    int result = F[n - 1][F[0].size() - 1];//最大价值
    cout << result << endl;

    //inp标记哪些物品在包中
    int j = C;
    int i = n - 1;
    while (i)
    {
        while (j && N[i] && j > W[i] && F[i][j] <= F[i][j - W[i]] + V[i]) //如果包含该物品,则一直循环看包含几个该物品
        {
            inp[i]++;
            j -= W[i];
            --N[i];
        }
        i--;//不包含该物品,则跳到下一个物品
    }

    //输出动态规划数组
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < F[0].size(); j++)
            cout << F[i][j] << " ";
        cout << endl;
    }

    return result;
}

int main() {
    vector<int> W{ 4,5,6,2,2 };
    vector<int> V{ 6,4,5,3,6 };
    int C = 9;
    int n = W.size();
    vector<int> inp(n, 0);//标记是否在包中
    cout << "1、01背包最大总价值:" << packages(C, W, V, n, inp) << endl;
    cout << "在背包中的物品编号: ";
    for (int i = 0; i < inp.size(); i++)
    {
        if (inp[i] == 1)
            cout << i << " ";
    }
    cout << endl;
    cout << "2、01背包滚动数组优化最大总价值,无法输出有哪些物品在背包中:" << packages_good(C, W, V, n) << endl;

    cout << endl;
    vector<int> inp1(n, 0);//标记是否在包中
    cout << "3、完全背包最大总价值:" << packages_full(C, W, V, n, inp1) << endl;
    cout << "输出在背包中物品: ";
    for (int i = 0; i < inp1.size(); i++)
    {
        cout << inp1[i] << " ";
    }
    cout << endl;

    cout << endl;
    vector<int> N{ 1,2,2,2,4 };//每个物品数量
    vector<int> inp2(n, 0);//标记是否在包中
    cout << "4、多重背包最大总价值:" << packages_multi(C, W, V, n, inp2, N) << endl;
    cout << "输出在背包中物品: ";
    for (int i = 0; i < inp2.size(); i++)
    {
        cout << inp2[i] << " ";
    }
    cout << endl;

    return 0;
}

原文地址:https://www.cnblogs.com/beixiaobei/p/10914211.html

时间: 2024-10-17 10:00:48

01背包、完全背包、多重背包的相关文章

01、完全、多重背包模板

背包问题: 背包总容量为W,有n件重量为weight[i],权值为value[i]的物品 1.01背包: 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放. 1 void ZeroOnePack (int weight,int value) 2 { 3 for (int w = W; w >= weight; w--) 4 dp[w] = max(dp[w - weight] + value, dp[w]); 5 } 2.完全背包: 每件物品有无限多个. void Complet

【CJWYH】RHL的背包题解(多重背包)

题面 [问题描述] CJ中学组织学生出去春游,作为学神的RHL自然不会放过这一大好时机,他有n种物品,第i件物品有c[i]个,每个体积为v[i],价值为w[i],RHL现在有一个体积为V的背包,他想让他带的东西价值之和最大,且体积之和不超过V,你能帮帮他吗?注意物体不能分割. [输入] 输入文件名为bag.in,分为若干行.第一行包含两个正整数n,V. 第二行到第n+1行分别描述第i种物品的数量c[i],体积v[i],价值w[i] [输出] 输出文件名为bag.out,一行输出一个整数,表示最大

01背包模板、全然背包 and 多重背包(模板)

转载请注明出处:http://blog.csdn.net/u012860063 贴一个自觉得解说不错的链接:http://www.cppblog.com/tanky-woo/archive/2010/07/31/121803.html 模版就直接贴代码: 01背包模板: /* 01背包问题 01背包问题的特点是,">每种物品仅有一件.能够选择放或不放. 01背包问题描写叙述: 有N件物品和一个容量为V的背包. 第i件物品的重量是c[i],价值是w[i]. 求解将哪些物品装入背包可使这些物品

hdu2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 (这个只是题目名字) (多重背包)

本文出自:http://blog.csdn.net/svitter 原题:http://acm.hdu.edu.cn/showproblem.php?pid=2191 题意:多重背包问题.转换成为01背包解.多重背包转化为01背包的关键在于把件数从整体中孤立出来作为一个新的个体,也就是说不管分类,有多少件就有多少种. AC代码: //============================================================================ // Na

【POJ1882】Stamps,灵活多重背包,详细题意!!!(题解也有)

我之所以发题解(题意),就是因为百度搜索上发的太少了,而且还不清晰,所以: 题意:我直接拿数据说话吧(可以直接看下面的大号粗体字,如果你语文够好的话.) 5 2 4 1 4 12 21 4 1 5 12 28 10 2 5 1 7 16 31 88 5 1 15 52 67 99 6 2 3 1 5 8 4 1 5 7 8 0 第一行 5 是最多能拿5张邮票,第二行2是有两组邮票. 第三行4是该组有4张邮票,然后4个数是4个面额. 第五行"10"开始就是下一组数据了,输入到"

DZY Loves Math II:多重背包dp+组合数

Description Input 第一行,两个正整数 S 和 q,q 表示询问数量.接下来 q 行,每行一个正整数 n. Output 输出共 q 行,分别为每个询问的答案. Sample Input 30 3 9 29 1000000000000000000 Sample Output 0 9 450000036 Hint 感谢the Loser协助更正数据对于100%的数据,2<=S<=2e6??,1<=n<=101810^{18}10?18??,1<=q<=10

【动态规划】背包问题(一) 01背包 完全背包 多重背包

一.01背包 有N件物品和一个容量为V的背包.第i件物品的价格(即体积,下同)是w[i],价值是c[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大. 这是最基础的背包问题,总的来说就是:选还是不选,这是个问题<( ̄ˇ ̄)/ 相当于用f[i][j]表示前i个背包装入容量为v的背包中所可以获得的最大价值. 对于一个物品,只有两种情况 情况一: 第i件不放进去,这时所得价值为:f[i-1][v] 情况二: 第i件放进去,这时所得价值为:f[i-1][v-c[i]]+w

有关货币问题的动态规划题目--有关01背包,完全背包,多重背包

背包dp:参考背包九讲以及给出一些题目 01背包 (先枚举物品,再逆序枚举容量) 给定n件物品和一个容量为V的背包,每件物品的体积是w[i],价值是va[i](1<=i<=n),求在不超过背包的容量的情况下,怎么选择装这些物品使得得到的价值最大? 例如:有5件物品,体积分别是{2,2,6,5,4},价值分别是{6,3,5,4,6} 递归式:F(i,v)=max(F(i-1,v), F(i-1,v-w[i])+va[i]),其中F(i,v)表示把前i种物品恰放入背包容量为v时取得的最大价值 把这

CRB and His Birthday 01背包 + 多重背包

CRB and His Birthday 题目抽象:背包问题,这里x个物品的价值是a * x + b (x > 0)  or 0 (x = 0). 分析:将物品按购买数量分类  1. 1件,  2 多件(>1).  对于一件的情况是01背包.  对于多件的情况是多重背包. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int dp

多重背包转换成完全背包和01背包

void CompletePack(int cost,int weight)   多重背包 { for(int i=cost;i<=m;i++) dp[i]=max(dp[i],dp[i-cost]+weight); } void ZeroOnePack(int cost,int weight)    01背包 { for(int i=m;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+weight); } void MultiplyPack(int cost,