$01背包详解$

Posted qf-breeze

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了$01背包详解$相关的知识,希望对你有一定的参考价值。

前言:DP 快接触半年了。 还是想起来把曾经虐我(01背包) 好好写写。
[ dp[i][j] = max( dp[i-1][j-w[i]] + c[i] , dp[i][j]);]
[ 这个方程熟悉吗qwq ]
[ 以及下面这个压维的。]
[ dp[j] = max( dp[j-w[i]] + c[i] , dp[j]);]

本文不多占篇幅 例题就写在这里。(抄袭代码后果自负

下面借鉴此处
技术图片

其中(F[i-1][j])表示前i-1件物品中选取若干件物品放入剩余空间为j的背包中所能得到的最大价值;
(F[i-1][j-C[i]]+W[i])表示前i-1件物品中选取若干件物品放入剩余空间为j-C[i]的背包中所能取得的最大价值加上第i件物品的价值。
根据第i件物品放或是不放确定遍历到第i件物品时的状态F[i][j]。
设物品件数为N,背包容量为V,第i件物品体积为C[i],第i件物品价值为W[i]。

所以得出代码

for(register int i=1; i<=n; i++)
        for(register int j=m; j>=c[i]; j--) dp[i][j] = max(dp[i-1][j-c[i]] + w[i] , dp[i][j]) ;

可是我们发现 i 这个变量其实是可以用滚动数组代替的。 因为只涉及到上一个变量。(即上一个状态。

所以的话 我们可以压维。 变成一维求01背包。

for(register int i=1; i<=n; i++)
    for(register int j=m; j>=c[i]; j--) dp[j] = max(dp[j-c[i]] + w[i] , dp[j]) ;

虽然时间复杂度不变 但是内存减少很多了。

01 背包的例题
P1910

// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define rep(i,j,n) for(register int i=j;i<=n;i++)
#define Rep(i,j,n) for(register int i=j;i>=n;i--)
#define low(x) x&(-x)
using namespace std ;
typedef long long LL ;
const int inf = INT_MAX >> 1 ;
inline LL In() { LL res(0) , f(1) ; register char c ;
#define gc c = getchar()
    while(isspace(gc)) ; c == '-' ? f = - 1 , gc : 0 ;
    while(res = (res << 1) + (res << 3) + (c & 15) , isdigit(gc)) ;
    return res * f ;
#undef gc
}


int v , m ;
int n ;
const int N = 1000 + 5 ;
int dp[N][N] ;

inline void Ot() {
    n = In() ;
    v = In() , m = In() ;
    rep(i,1,n) {
        int x = In() , y = In() , z = In() ;
        Rep(i,v,y)
            Rep(j,m,z) dp[i][j] = max(dp[i-y][j-z] + x , dp[i][j]) ;
    }
    cout << dp[v][m] << endl ;
}
signed main() {
    return Ot() , 0 ;
}

P2871

// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define rep(i,j,n) for(register int i=j;i<=n;i++)
#define Rep(i,j,n) for(register int i=j;i>=n;i--)
#define low(x) x&(-x)
using namespace std ;
typedef long long LL ;
const int inf = INT_MAX >> 1 ;
inline LL In() { LL res(0) , f(1) ; register char c ;
#define gc c = getchar()
    while(isspace(gc)) ; c == '-' ? f = - 1 , gc : 0 ;
    while(res = (res << 1) + (res << 3) + (c & 15) , isdigit(gc)) ;
    return res * f ;
#undef gc
}


int v , m ;
int n ;
const int N = 400 + 5 ;
int dp[N][N] ;

inline void Ot() {
    v = In() , m = In() ;
    n = In() ;
    rep(i,1,n) {
        int x = In() , y = In() , z = In() ;
        Rep(i,v,x)
            Rep(j,m,y) dp[i][j] = max(dp[i-x][j-y] + z , dp[i][j]) ;
    }
    cout << dp[v][m] << endl ;
}
signed main() {
    return Ot() , 0 ;
}

P1048

#include <bits/stdc++.h>
#define rep(i,j,n) for(register int i=j;i<=n;i++)
#define Rep(i,j,n) for(register int i=j;i>=n;i--)
#define low(x) x&(-x)
using namespace std ;
typedef long long LL ;
const int inf = INT_MAX >> 1 ;
inline LL In() { LL res(0) , f(1) ; register char c ;
#define gc c = getchar()
    while(isspace(gc)) ; c == '-' ? f = - 1 , gc : 0 ;
    while(res = (res << 1) + (res << 3) + (c & 15) , isdigit(gc)) ;
    return res * f ;
#undef gc
}

int T , M ;
const int N = 1000 + 5 ;
int dp[N] ;
inline void Ot() {
    T = In() , M = In() ;
    for(register int i=1;i<=M;i++) {
        int x = In() , y = In() ;
        for(register int j=T;j>=x;j--) dp[j] = max(dp[j-x]+y, dp[j]) ;
    }
    cout << dp[T] << endl ;
}
signed main() {
    return Ot() , 0 ;
}

P1060

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define f(i,j,n) for(int i=j;i<=n;i++)
#define fa(i,j,n) for(int i=j;i>=n;i--)
using namespace std;
int w[30],v[30],f[50000];
int n,m;
int main() {
    cin>>m>>n;
    f(i,1,n) {
        cin>>v[i]>>w[i];
        w[i]*=v[i];
    }
    f(i,1,n)
        fa(j,m,v[i]) f[j]=max(f[j],f[j-v[i]]+w[i]);
    cout<<f[m]<<endl;
    return 0;
}

P1877

// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define rep(i,j,n) for(register int i=j;i<=n;i++)
using namespace std;
typedef long long LL;
inline LL read(){ LL x=0;int f(1);char ch=getchar();
    while(!isdigit(ch)) { if(ch=='-') f=-1;
        ch=getchar();
    }
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return x*f;
}

int n;
int Begin,Max;
int a[1<<6];
int dp[1<<6][1<<12];
signed main(){
    memset(dp,0,sizeof(dp));
    n=read(); Begin=read(); Max=read();
    dp[0][Begin]=1;
    rep(i,1,n) a[i]=read(); 
    rep(i,1,n) rep(j,0,Max)  {
        if (j+a[i] <= Max) dp[i][j]=dp[i][j]||dp[i-1][j+a[i]];
        if (j-a[i] >= 0)   dp[i][j]=dp[i][j]||dp[i-1][j-a[i]];
    }
    LL ans = -0x7f;
    for(register int i=1;i<=Max;i++) {
        if(dp[n][i]) ans = i;
    }
    if ( ans != -0x7f) cout << ans << endl ;
    else puts("-1") ; 
    return 0;
}

带点[并查集]的

P1455

// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
inline LL read () { LL res = 0 ;int f (1) ;char ch = getchar ();
    while (!isdigit(ch)) { if (ch == '-') f = -1 ;ch = getchar();}
    while (isdigit(ch)) res = (res << 1) + (res << 3) + (ch ^ 48) ,ch = getchar(); return res * f ;
}
int n,m,we,fa[10005],w[10005],c[10005],dp[10005];
inline int find(int x){
    if(fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}
inline void merge(int x,int y){
    int f1=find(x),f2=find(y);
    if(f1!=f2)fa[f1]=f2,c[f2]+=c[f1],w[f2]+=w[f1];
}
int main(){
    n=read(),m=read(),we=read();
    for(register int i=1;i<=n;i++) fa[i]=i;
    for(register int i=1;i<=n;i++) c[i]=read(),w[i]=read();
    for(register int i=1;i<=m;i++){
        int u=read(),v=read();
        merge(u,v);
    }
    for(register int i=1;i<=n;i++) if(fa[i]==i)
    for(register int j=we;j>=c[i];j--) dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
    cout << dp[we] << endl ;
    return 0;
}

以及这道题

以上是关于$01背包详解$的主要内容,如果未能解决你的问题,请参考以下文章

动态规划1 —— 01背包详解

求背包问题详解

背包之01背包完全背包多重背包详解

动态规划之01背包详解解题报告

动态规划01背包问题(例子详解)

动态规划之01背包详解