dp背包(01背包,完全背包,多重背包,混合背包,二进制优化多重背包)

一、01背包模板

洛谷 P1048 采药

#include <bits/stdc++.h>

using namespace std;
int w[500],c[500],dp[500];
int v,n;
int main()
{
   cin>>v>>n;
   for(int i=1;i<=n;i++)
    cin>>w[i]>>c[i];
   for(int i=1;i<=n;i++)//i表示,在前i个物体中选择放入背包
    for(int j=v;j>=w[i];j--)//背包从大到小的记忆化搜索
    //背包问题是一种贪心
    //这里的比较不装这个东西(并且目前为止价值最大)与装了这个东西的两者比较
    //并且将其中最优解赋值给dp
    //dp[j-w[i]]是不装这个东西所能达到的最大价值
    //文字概述就是背包除开装这个物体的体积所能达到的最大价值,毫无疑问是最优解
    dp[j]=max(dp[j],dp[j-w[i]]+c[i]);

    cout <<dp[v] << endl;
    return 0;
}

二、完全背包

完全背包问题-DP

与01背包的区别是第二重循环是从w[i]开始,会重复

#include <bits/stdc++.h>

using namespace std;
int n,m,i,j,t,ans,tmp1,tmp2,w[101],c[35],dp[205];

int main()
{
    ios::sync_with_stdio(false);
    cin>>m>>n;
    for(int i=1;i<=n;i++)cin>>w[i]>>c[i];//w为重量,c为价值
    for(int i=1;i<=n;i++)
        for(int j=w[i];j<=m;j++)
    {
        dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
    }
    cout<<"max="<<dp[m]<<endl;
    return 0;
}

三、多重背包

庆功会-DP-多重背包

有两种方法

1.直接增添一重循环,其它与01背包相同

#include <bits/stdc++.h>

using namespace std;
const int N=6e4+5;//因为m最大为6000
int n,m,i,j,t,ans,tmp1,tmp2,w[N],c[N],dp[N],a[N];

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>w[i]>>c[i]>>a[i];//w为重量,c为价值
    for(int i=1;i<=n;i++)
        for(int k=1;k<=a[i];k++)
        for(int j=m;j>=w[i];j--)
    {
        dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
    }
    cout<<dp[m]<<endl;
    return 0;
}

2.二进制优化

这种方法可以节省时间

#include <bits/stdc++.h>
using namespace std;
int w[5001],c[5001],dp[5001];
int main()
{
  int n,m;
  int v,s,t,p=0;
  cin>>n>>m;
  for(int i=1;i<=n;i++)
  {
      cin>>v>>t>>s;
      int x=1;
      while(s-x>0)
      {
          s=s-x;
          w[++p]=x*v;
          c[p]=x*t;
          x=x*2;
      }
      w[++p]=s*v;
      c[p]=s*t;
  }
  for(int i=1;i<=p;i++)
        for(int j=m;j>=w[i];j--)
        dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
  cout<<dp[m]<<endl;
  return 0;
}

四、混合背包

樱花-DP-背包

#include <bits/stdc++.h>

using namespace std;
const int N=1e6+5;//因为m最大为6000
int rest,k,cnt,w0,c0,s,n,h1,h2,m1,m2,w[N],c[N],dp[N],a[N];
int main()
{
    scanf("%d:%d %d:%d %d",&h1,&m1,&h2,&m2,&n);//scanf可以读:
    int time=(h2-h1)*60+(m2-m1);
    while(n--)
    {
        cin>>w0>>c0>>s;
        if(s==0)
        {
            for(int j=w0;j<=time;j++)
                dp[j]=max(dp[j],dp[j-w0]+c0);
        }
        else
        {
            rest=s;
            k=1;
            while(rest>=k)
            {
                w[++cnt]=w0*k;
                c[cnt]=c0*k;
                rest=rest-k;
                k=k*2;
            }
            if(rest>0){w[++cnt]=w0*rest;c[cnt]=c0*rest;}
        }
    }
    for(int i=1;i<=cnt;i++)//01背包处理
        for(int j=time;j>=w[i];j--)
        dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
    cout<<dp[time]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhoucheng_123/article/details/104211612