洛谷 P1776 宝物筛选 解题报告

关于多重背包的优化问题。

首先多重背包很容易想到这样暴力转移:

for(int i=1;i<=n;i++)
{
    for(int k=1;k<=a[i].num;k++)
    {
        for(int j=m;j>=a[i].v;j--)
        {
                dp[j]=max(dp[j],dp[j-a[i].v]+a[i].w);
        }
    }
}

但这个题是会T的。

于是,有了两种对多重背包的优化:分别是二进制拆分和单调队列优化。


一、二进制拆分:

把每种物品的数量拆分成二进制的形式,这样就可以在表示出所有数量的前提下,保证物品数最小。

证明略,具体代码如下:(非常好理解)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define ll long long
#define ui unsigned int
#define ull unsigned long long
#define R register
using namespace std;
namespace chu_xuan{
    void swap(int &a,int &b){R int tmp=a;a=b,b=tmp;}
    void read(int &a) {a=0;int b=1,c=getchar(); while(c>'9'||c<'0'){if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b;}
    int In() {int a=0,b=1,c=getchar(); while(c>'9'||c<'0'){if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();return a*b;}
    int max(int a,int b){return a>b?a:b;}
    int min(int a,int b){return a>b?b:a;}
}using namespace chu_xuan;

const int N=1e6+5;
int n,m,f[N],v[N],w[N],cnt;

int main()
{
    read(n);read(m);
    for(int i=1,a,b,c;i<=n;++i)
    {
        read(a);read(b);read(c);
        for(int j=1;j<=c;j<<=1)
        {
            v[++cnt]=j*a,w[cnt]=j*b;
            c-=j;
        }
        if(c) v[++cnt]=a*c,w[cnt]=b*c;
    }
    for(int i=1;i<=cnt;i++)
    {
        for(int j=m;j>=w[i];j--)
        {
            f[j]=max(f[j],f[j-w[i]]+v[i]);
        }
    }
    cout<<f[m]<<'\n';
    return 0;
}
二进制拆分(宝物筛选)

二、单调队列优化:

待填坑

猜你喜欢

转载自www.cnblogs.com/chu-xuan/p/10556414.html