背包dp

背包dp的模型可以看作是“给定n个物品,从中选择一定的物品”。

我们从以下几个角度考虑:

1.已经选择的物品

2.背包容量

dp数组常常保存最大价值

0/1背包(一个物品只选一次)

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1010;

int f[maxn] = {};    //默认全为0,这样后面就不需要再初始化
int n = 0, m = 0;    //n件物品,m为背包总容量
int v[maxn] = {}, w[maxn] = {};    //v表示第i件物品体积,w为第i件物品价值

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=m; j>=v[i]; j--)
        { 
            f[j] = max(f[j], f[j-v[i]] + w[i]);
        }
    }
    printf("%d", f[m]);

    return 0;
}

 完全背包(物品数量无限制)

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1010;

int f[maxn] = {};    //默认全为0,这样后面就不需要再初始化
int n = 0, m = 0;    //n件物品,m为背包总容量
int v[maxn] = {}, w[maxn] = {};    //v表示第i件物品体积,w为第i件物品价值

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=v[i]; j<=m; j++)
        { 
            f[j] = max(f[j], f[j-v[i]] + w[i]);
        }
    }
    printf("%d", f[m]);

    return 0;
}

多重背包(给定物品数量)

直接转化为0/1背包

#include <bits/stdc++.h>
using namespace std;

const int maxn = 110;

int n = 0, m = 0;	 
int f[maxn] = {};	 
int v[maxn] = {}, w[maxn] = {}, s[maxn] = {};	 

int main()
{	
	scanf("%d%d", &n, &m);
	for(int i=1; i<=n; i++)
	{
		scanf("%d%d%d", &v[i], &w[i], &s[i]);
	}

	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=s[i]; j++)
		{
			for(int k=m; k>=v[i]; k--)
			{
				f[k] = max(f[k], f[k-v[i]] + w[i]);
			}			
		}
	}
	printf("%d", f[m]);

	return 0;
}

多重背包 & 二进制拆分

#include <bits/stdc++.h>
using namespace std;

const int maxn = 15000;
const int maxm = 2010;

int n = 0, m = 0;     
int f[maxm] = {};     
int v[maxn] = {}, w[maxn] = {}, s[maxn] = {}, cnt = 0;     

int main()
{    
    int vi = 0, wi = 0, si = 0;
    scanf("%d%d", &n, &m);
    //二进制拆分
    for(int i=1; i<=n; i++)
    {
        scanf("%d%d%d", &vi, &wi, &si);
        if(si > m / vi) si = m / vi;
        for(int j=1; j<=si; j<<=1)
        {
            v[++cnt] = j * vi;
            w[cnt] = j * wi;
            si -= j;
        }
        if(si > 0)
        {
            v[++cnt] = si * vi;
            w[cnt] = si * wi;
        }
    }
    
    //0/1背包
    for(int i=1; i<=cnt; i++)
    {
        for(int j=m; j>=v[i]; j--)
        {
            f[j] = max(f[j], f[j-v[i]] + w[i]);
        }    
    }
    printf("%d", f[m]);

    return 0;
}

 分组背包

分组背包 & 终极版1

#include <bits/stdc++.h>
using namespace std;

const int maxn = 40;
const int maxm = 210;

//分组背包
int n = 0, m = 0, t = 0;     
int v[maxn] = {}, c[maxn] = {}, g[15][maxn] = {};
int f[maxm] = {};

int main()
{     
    int x = 0;
    scanf("%d%d%d", &m, &n, &t); 
    for(int i=1; i<=n; i++)
    {
        scanf("%d%d%d", &v[i], &c[i], &x);
        g[x][++g[x][0]] = i;
    }
    
    for(int i=1; i<=t; i++)
    {
        for(int j=m; j>=0; j--)
        {
            for(int k=1; k<=g[i][0]; k++)
            {
                if(j >= v[g[i][k]]) 
                {
                    x = g[i][k];
                    f[j] = max(f[j], f[j-v[x]] + c[x]);    
                }
            }
        }
    }
    printf("%d", f[m]);

    return 0;
}

分组背包 & 终极版2

#include <bits/stdc++.h>
using namespace std;

const int maxn = 110;
const int maxm = 110;

int n = 0, m = 0;     
int f[maxm] = {};     
int v[maxn][maxn] = {}, w[maxn][maxn] = {}, s[maxn] = {};     

int main()
{     
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++)
    {
        scanf("%d", &s[i]);
        for(int j=1; j<=s[i]; j++)
        {
            scanf("%d%d", &v[i][j], &w[i][j]);
        }
    }
    
    for(int i=1; i<=n; i++)    //阶段
    {
        //i和j共同构成状态
        for(int j=m; j>=0; j--)
        {
            for(int k=1; k<=s[i]; k++)    //k是决策
            {
                if(j >= v[i][k])
                {
                    f[j] = max(f[j], f[j-v[i][k]] + w[i][k]);
                }
            }
        }
    }
    printf("%d", f[m]);

    return 0;
}

二维费用背包

#include <bits/stdc++.h>
using namespace std;

const int maxn = 60;
const int maxm = 410;

//二维费用背包
int n = 0, v = 0, m = 0;     
int a[maxn] = {}, b[maxn] = {}, c[maxn] = {};
int f[maxm][maxm] = {};

int main()
{     
    scanf("%d%d%d", &v, &m, &n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d%d%d", &a[i], &b[i], &c[i]);
    }
    
    for(int i=1; i<=n; i++)
    {
        for(int j=v; j>=a[i]; j--)
        {
            for(int k=m; k>=b[i]; k--)
            {
                f[j][k] = max(f[j][k], f[j-a[i]][k-b[i]] + c[i]);
            }
        }
    }
    printf("%d", f[v][m]);

    return 0;
}

 混合背包(将背包都使用二进制拆分转成0/1背包计算) 

#include<bits/stdc++.h>
using namespace std;
int m,n,cnt;
int v[100000],w[100100],s[101000],f[100050];
int main(){
    int vi=0,wi=0,ni=0;
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&vi,&wi,&ni);
        if(ni>m/vi||ni==0) ni=m/vi;
        for(int j=1;j<=ni;j<<=1){
            v[++cnt]=j*vi;
            w[cnt]=j*wi;
            ni-=j;
        }
        if(ni>0){
            v[++cnt]=ni*vi;
            w[cnt]=ni*wi;
        }
    }
    for(int i=1;i<=cnt;i++){
        for(int j=m;j>=v[i];j--){
        f[j]=max(f[j],f[j-v[i]]+w[i]);
        }
    }
    printf("%d",f[m]);
    return 0;
}

 

posted on 2024-02-17 11:12  风ffff  阅读(11)  评论(0编辑  收藏  举报