背包问题--01背包 (Bitset的优化) 多重背包 (二进制优化)

01背包问题:

题目链接

题意:n个物品一个m容量的背包,n个物品有need[i]的体积消耗,以及权值value[i] ,问m容量装n个物品能得到的最大权值是多少。

做法:01背包介绍:博客

代码:

#include
using namespace std;
typedef long long ll;
inline ll read()
{
	ll x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
	return w==1?x:-x;
}
const int N=5e2+10,M=1e5+10;
int n,m,dp[M],need[N],value[N];
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;++i){
        need[i]=read(),value[i]=read();
    }

    for(int i=1;i<=n;++i){
        for(int j=m;j>=need[i];--j){
            dp[j]=max(dp[j],dp[j-need[i]]+value[i]);
        }
    }
    printf("%d\n",dp[m]);
}

Bitset优化01背包

需要更正一个地方是,这里的bitset优化的不是朴素的01背包,而是只有01状态的多重背包。

之前的博客:[博客C回到过去]  [题目链接 C回到过去]

#include
using namespace std;
typedef long long ll;
const int N = 100010;
bitsetf[451],g[451];


int a[N],cnt[N],ans[N],anss;
int main() {

    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;++i) scanf("%d",&a[i]);

    sort(a + 1,a + n + 1);


    int tot = 0;
    for(int i = 1;i <= n;++i) {
        if(a[i] != a[i - 1])  a[++tot] = a[i];
        cnt[tot]++;
    }

    n = tot;

    f[0][0] = 1;
    g[n + 1][0] = 1;

    for(int i = 1;i <= n;++i) {
        int k = a[i],tmp = cnt[i];//f[i]|=f[i]<= 1;--i) {
        int k = a[i],tmp = cnt[i];

        g[i] = g[i + 1];

        for(int j = 1;j <= tmp;tmp -= j,j <<= 1,k <<= 1) g[i] |= g[i] << k;

        g[i] |= g[i] << (a[i] * tmp);
    }

    for(int i = 1;i <= n;++i) {
        int flag = 0;
        for(int j = 0;j <= m;++j) {
            if(f[i - 1][j] & g[i + 1][m - j]) {
                flag = 1;break;
            }
        }
        if(!flag) ans[++anss] = a[i];
    }

//  for(int i = 1;i <= n;++i) printf("%d %d\n",a[i],cnt[i]);

    printf("%d\n",anss);
    for(int i = 1;i <= anss;++i) printf("%d ",ans[i]);
    return 0;
}

多重背包

来一道例题:题目链接

题意:n经费,m种类的大米,每种大米有 金额p[i] 重量h[i] 以及最多的袋数c[i]   问在n经费内 时能得到的最大重量是多少?

做法:朴素的多重背包

#include
using namespace std;

typedef long long ll;
const int N=1e2+10;
int n,m,p[N],h[N],c[N],dp[N];
inline ll read()
{
	ll x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
	return w==1?x:-x;
}

int main()
{
    int _=read();while(_--)
    {
        n=read(),m=read();
        for(int i=1;i<=m;++i) p[i]=read(),h[i]=read(),c[i]=read();

        for(int i=0;i<=n;++i) dp[i]=0;

        for(int i=1;i<=m;++i){//枚举种类
            for(int j=1;j<=c[i];++j){//c[i]次的01背包
                for(int k=n;k>=p[i];--k){
                    dp[k]=max(dp[k],dp[k-p[i]]+h[i]);
                }
            }
        }
        printf("%d\n",dp[n]);
    }
}

二进制优化多重背包

题目链接:牛客E题

背包问题--01背包 (Bitset的优化) 多重背包 (二进制优化)_第1张图片

这部分做法参考来自:wiki

背包问题--01背包 (Bitset的优化) 多重背包 (二进制优化)_第2张图片

背包问题--01背包 (Bitset的优化) 多重背包 (二进制优化)_第3张图片

#include
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false)
#define pb push_back
#define mk make_pair
const int N = 1e5+10;
const int mod = 1e9+7;

int n;
int t[N], q[N], s[N];
int dp[2000];

int main(){
    int h1, m1, h2, m2;
    scanf("%d:%d %d:%d %d", &h1, &m1, &h2, &m2, &n);
    if(m1 > m2){
        m2 += 60; h2--;
    }
    int sumt = (h2-h1)*60 + m2 - m1;
    for(int i = 0; i <= sumt; i++){
        dp[i] = 0;
    }
    for(int i = 1; i <= n; i++){
        scanf("%d%d%d", t+i, q+i, s+i);
    }
    int index = 0;
    for(int i = 1; i <= n; i++){
        int c = 1;
        if(s[i] == 0 || s[i] >= sumt/t[i]) {
            for(int j = t[i]; j <= sumt; j++){//普通的完全背包
                dp[j] = max(dp[j], dp[j-t[i]] + q[i]);
            }
        }
        else{
            while(s[i] - c > 0){//多重背包的二进制优化 
                s[i] -= c;
                for(int j = sumt; j >= c*t[i]; j--){
                    dp[j] = max(dp[j], dp[j-c*t[i]] + c*q[i]);
                }
                c *= 2;
            }
            if(s[i]){
                for(int j = sumt; j >= s[i]*t[i]; j--){
                    dp[j] = max(dp[j], dp[j-s[i]*t[i]] + s[i]*q[i]);
                }
            }
        }
    }
    printf("%d\n", dp[sumt]);
    return 0;
}

 

你可能感兴趣的:(dp---背包问题)