栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

经典算法之背包求最大最小价值问题

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

经典算法之背包求最大最小价值问题

《经典算法之背包求最大最小价值问题》

这里顺便引入基础版各背包模型:背包问题详解
进阶版: 背包计数问题

1、从前 i 个物品中选,且总体积不超过 j 的最大价值,初始化是 f[i , k] = 0,0 <= i <= n, 0 <= k <= m(只会求价值的最大值) 01背包问题
例子:给你一堆物品,每个物品有一定的体积和对应的价值,每个物品只能选一个,求总体积不超过 m 的最大价值

输入 :n 个物品, 总体积不超过 m, 接下来是 n 个物品的体积和价值

4 5
1 2
2 4
3 4
4 5

输出:最大价值

8

二维代码

#include 
using namespace std;

const int N = 110;

int n, m;
int f[N][N];

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

状态压缩

#include 
using namespace std;

const int N = 110;

int n, m;
int f[N];

int main() {
    
    cin >> n >> m;
    
    for (int i = 1; i <= n; i ++ ) {
        int v, w;
        cin >> v >> w;
        for (int j = m; j >= v; j -- ) {
            f[j] = max(f[j], f[j - v] + w);
        }
    }
    
    cout << f[m];
    
    return 0;
}
2、从前 i 个物品中选,且总体积恰好是 j 01背包问题

(1)求价值最大值:初始化 f[0][0] = 0, 其余是 -INF

例子:给你一堆物品,每个物品有一定的体积和对应的价值,每个物品只能选一个,求总体积恰好是 j 的最大价值

输入

4 5
1 2
2 4
3 4
4 5

输出

8

二维代码

#include 
using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n, m;
int f[N][N];

int main() {
    
    cin >> n >> m;
    
    
    memset(f, -0x3f, sizeof f);
    f[0][0] = 0;
    for (int i = 1; i <= n; i ++ ) {
        int v, w;
        cin >> v >> w;
        for (int j = 0; j <= m; j ++ ) {
            f[i][j] = f[i - 1][j]; //先不选从上一状态转移过来,即最开始一个物品的话,就是从第 0 行转移,不能敲好等于自身体积,则会被置为 -INF
            if (j >= v) f[i][j] = max(f[i][j], f[i - 1][j - v] + w); //再判断当前是否可以加入当前这个物品
        }
    }
    
    cout << f[n][m];
    
    return 0;
}

状态压缩

#include 
using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n, m;
int f[N];

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

(2)求价值最小值:初始化 f[0][0] = 0, 其余是 INF

例子:给你一堆物品,每个物品有一定的体积和对应的价值,每个物品只能选一个,求总体积恰好是j的最小价值

输入

4 5
1 2
2 4
3 4
4 5

输出

7

二维代码

#include 
using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n, m;
int f[N][N];

int main() {
    
    cin >> n >> m;
    
    memset(f, 0x3f, sizeof f);
    f[0][0] = 0;
    for (int i = 1; i <= n; i ++ ) {
        int v, w;
        cin >> v >> w;
        for (int j = 0; j <= m; j ++ ) {
            f[i][j] = f[i - 1][j];
            if (j >= v) f[i][j] = min(f[i][j], f[i - 1][j - v] + w);
        }
    }
    
    cout << f[n][m];
    
    return 0;
}

状态压缩

#include 
using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n, m;
int f[N];

int main() {
    
    cin >> n >> m;
    
    memset(f, 0x3f, sizeof f);
    f[0] = 0;
    for (int i = 1; i <= n; i ++ ) {
        int v, w;
        cin >> v >> w;
        for (int j = m; j >= v; j -- ) {
            f[j] = min(f[j], f[j - v] + w);
        }
    }
    
    cout << f[m];
    
    return 0;
}
完全背包问题 (1)求价值最大值:初始化 f[0][0] = 0, 其余是 -INF
例子:给你一堆物品,每个物品有一定的体积和对应的价值,每个物品可以选无数多个,求总体积恰好是 j 的最大价值

输入

4 5
1 2
2 4
3 4
4 5

输出

10

二维代码

#include 
#include 

using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n, m;
int f[N][N];

int main()
{
    cin >> n >> m;

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

    cout << f[n][m] << endl;

    return 0;
}

☆完全背包问题的经典状态压缩过程
f[i , j ] = max( f[i-1,j] , f[i-1,j-v]+w ,  f[i-1,j-2*v]+2*w , f[i-1,j-3*v]+3*w , .....)
f[i , j-v]= max(            f[i-1,j-v]   ,  f[i-1,j-2*v] + w , f[i-1,j-3*v]+2*w , .....)
由上两式,可得出如下递推关系: 
                        f[i][j]=max(f[i,j-v] + w , f[i-1][j])  //即选与不选两种状态

状态压缩

#include 
#include 

using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n, m;
int f[N];

int main()
{
    cin >> n >> m;
    

    memset(f, -0x3f, sizeof f);
    f[0] = 0;

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

    cout << f[m] << endl;

    return 0;
}

(2)求价值最小值:初始化 f[0][0] = 0, 其余是 INF
例子:给你一堆物品,每个物品有一定的体积和对应的价值,每个物品可以选无数多个,求总体积恰好是 j 的最小价值

输入

4 5
1 2
2 4
3 4
4 5

输出

7

二维代码

#include 

using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n, m;
int f[N][N];

int main()
{
    cin >> n >> m;

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

    cout << f[n][m];

    return 0;
}

状态压缩

#include 
#include 

using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n, m;
int f[N];

int main()
{
    cin >> n >> m;

    memset(f, 0x3f, sizeof f);
    f[0] = 0;

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

    cout << f[m] << endl;

    return 0;
}

3、从前 i 个物品中选,且总体积至少是 j ,初始化是 f[0][0] = 0, 其余是 INF(只会求价值的最小值)
例子:给你一堆物品,每个物品有一定的体积和对应的价值,每个物品可以选无数多个,求总体积至少是j的最小价值

输入

4 5
1 2
2 4
3 4
4 5

输出

7

题解

	1.初始化时:和恰好等于体积 j 的初始化方式相同,因为至少包含了敲好等于,而计算超出部分时,则需要通过 f[i][0] 转移过来
	2.max(0,  j  -  v) ,即当体积此时不能装下时, 表示超出了,也满足,所以直接可以从f[i][0] 表示过来,再 + w, 表示可以装,只是体积超出了。
	第一种背包( 1 2 ): 0 2 4 6 8 10 
	第二个背包( 2 4 ): 0 2 4 6 8 10 
	第三个背包( 3 4 ): 0 2 4 4 6 8 
	第四个背包( 4 5 ): 0 2 4 4 5 7 

二维代码

#include 
#include 

using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n, m;
int f[N][N];

int main()
{
    cin >> n >> m;
	
    memset(f, INF, sizeof f);
    f[0][0] = 0;

    for (int i = 1; i <= n; i ++ )
    {
        int v, w;
        cin >> v >> w;
        for (int j = 0; j <= m; j ++ )
        {
            f[i][j] = min(f[i - 1][j], f[i][max(0, j - v)] + w);//即使物品体积比j大,j - v < 0,也能选,等价于f[i - 1][0]
        }
    }

    cout << f[n][m] << endl;

    return 0;
}

状态压缩

#include 
#include 

using namespace std;

const int N = 110, INF = 0x3f3f3f3f;

int n, m;
int f[N];

int main()
{
    cin >> n >> m;
    

    memset(f, 0x3f, sizeof f);
    f[0] = 0;

    for (int i = 1; i <= n; i ++ )
    {
        int v, w;
        cin >> v >> w;
        for (int j = m; j >= 0; j -- )
        {
            f[j] = min(f[j], f[max(0, j - v)] + w);//即使物品体积比j大,j - v < 0,也能选,等价于f[0]
        }
    }

    cout << f[m] << endl;

    return 0;
}

如有错误之处,欢迎指正~~~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/862575.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号