背包问题总结篇

1.混合了贪心思想的背包入门

nefu1028暑假计划 01背包

给定工作开始时间、完成时间、给的工资,工作不能重叠,求最大收益。

一维Dp表示截止到当前时间的最大收益,但是事先要对结构体按结束时间排序,防止前一状态没有值

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int dp[1005];
    struct money
    {
         int l,r,w;
    }a[1005];
    int cmp(money x,money y)//排序都快忘了怎么写了= =
    {
         if(x.r==y.r) return x.l<y.l;
         return x.r<y.r;
    }
    int main()
    {
       //  freopen("cin.txt","r",stdin);
         int n,t,m;
         scanf("%d",&t);  

              while(t--)
              {
                   memset(dp,0,sizeof(dp));
                   scanf("%d%d",&m,&n);//假期时间m和可做的工作数n
                   for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w);
                   sort(a+1,a+1+n,cmp);
                   for(int i=1;i<=n;i++)
                   {
                        for(int j=m;j>=a[i].r;j--)
                        {
                             dp[j]=max(dp[j],dp[j]-(dp[a[i].r]-dp[a[i].l-1])+a[i].w);//重点的重点
                        }
                   }
                   printf("%d\n",dp[m]);
              }  

    }  

2.凑一半  裸的背包

UVA 562 Dividing coins 01背包

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    using namespace std;
    int price[50500],f[50500],n,t,sum;
    int dp()
    {
         memset(f,0,sizeof(f));
         for(int i=1;i<=n;i++)
         {
              for(int j=sum;j>=price[i];j--)
              {
                   if(f[j]<f[j-price[i]]+price[i])
                   f[j]=f[j-price[i]]+price[i];
              }
         }
         return f[sum];
    }
    int main()
    {
       // freopen("cin.txt","r",stdin);
        while(~scanf("%d",&t))
        {
             while(t--)
             {
                  scanf("%d",&n);
                   sum=0;
                   for(int i=1;i<=n;i++)
                   {
                        scanf("%d",&price[i]);
                        sum+=price[i];
                   }
                   int cnt=sum;
                   sum=(sum+1)/2;
                   cnt=dp()*2-cnt;
                   if(cnt<0) cnt=-cnt;
                   printf("%d\n",cnt);
             }
        }
        return 0;
    }  

3.概率不超过某值的最大收益

hdu2955 Robberies 01背包的变形

加法变成乘法而已

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    double pj[1050],dp[100500],p,rate;
    int t,m[1050],n,sum;
    double max(double a,double b)
    {
         if(a<b) return b;
         else return a;
    }
    int main()
    {
       // freopen("cin.txt","r",stdin);
        while(~scanf("%d",&t))
        {
             while(t--)
             {
                  memset(dp,0,sizeof(dp));
                  dp[0]=1;
                  sum=0;
                  scanf("%lf%d",&p,&n);
                  p=1-p;
                  for(int i=0;i<n;i++)
                  {
                       scanf("%d%lf",&m[i],&pj[i]);
                       pj[i]=1-pj[i];
                       sum+=m[i];
                  }
                  for(int i=0;i<n;i++)
                  {
                       for(int j=sum;j>=m[i];j--)
                        dp[j]=max(dp[j],dp[j-m[i]]*pj[i]);
                  }
                  for(int i=sum;i>=0;i--)
                  {
                       if(dp[i]>p)
                       {
                            printf("%d\n",i);
                            break;
                       }
                  }
             }
        }
        return 0;
    }  

4."混合背包"

2015多校联合第十场hdu5410CRB and His Birthday 01背包+完全背包

完全背包中若选择某种物品选一次加一个a[i],另加b[i]的价值,只加一次。在第二层for循环中先进行一次01背包算b[i]+a[i],再进行一次多重背包算a[i]

    #include <iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int dp[2005],cost[2005],a[2005],b[2005];
    int main()
    {
        //freopen("cin.txt","r",stdin);
        int t,m,n;
        while(cin>>t)
        {
            while(t--)
            {
                cin>>m>>n;
                memset(dp,0,sizeof(dp));
                for(int i=0;i<n;i++) cin>>cost[i]>>a[i]>>b[i];
                for(int i=0;i<n;i++)
                {
                    for(int j=m;j>=cost[i];j--)
                        if(dp[j]<dp[j-cost[i]]+a[i]+b[i]) dp[j]=dp[j-cost[i]]+a[i]+b[i];
                    for(int j=cost[i];j<=m;j++)
                        if(dp[j]<dp[j-cost[i]]+a[i]) dp[j]=dp[j-cost[i]]+a[i];
                }
                cout<<dp[m]<<endl;
            }
        }
        return 0;
    }  

5.01背包入门题

0-1背包:nefu19采药hdu2546饭卡

    #include <iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n;
    int price[1005],f[1005];
    int m;
    int main()
    {
        //freopen("data.in.txt","r",stdin);
        while(~scanf("%d",&n)&&n)
        {
             for(int i=1;i<=n;i++) scanf("%d",&price[i]);
             scanf("%d",&m);
             f[0]=0;
             //for(int i=1;i<=n;i++) f[i]=-999999;
             memset(f,0,sizeof(f));
             sort(price+1,price+n+1);
             for(int i=1;i<=n-1;i++)
             {
                  for(int v=m-5;v>=price[i];v--)
                   f[v]=max(f[v],f[v-price[i]]+price[i]);
             }  

             if(m>=5) printf("%d\n",m-f[m-5]-price[n]);
             else printf("%d\n",m);
        }
        return 0;
    }  
    #include <iostream>
    #include<cstdio>
    #include<cstring>
    //#define INF 0x7ffffff
    using namespace std;
    int cost[1005];
    int price[1005];
    int f[1005];
    int main()
    {
        int m,t;
        while(~scanf("%d%d",&t,&m))
        {
             f[0]=0;
             memset(f,0,sizeof(f));
             //for(int i=1;i<=m;i++) f[i]=-999999;
             for(int i=1;i<=m;i++) scanf("%d%d",&cost[i],&price[i]);
             for(int i=1;i<=m;i++)
             {
                  for(int v=t;v>=cost[i];v--)
                    f[v]=max(f[v],f[v-cost[i]]+price[i]);
              }
              printf("%d\n",f[t]);
        }
        return 0;
    }

6.同第二题  凑一半

hdu1171big events in hdu【多重背包模板】

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[50005];
int value[60],num[60];
int n,total,sum;
void zero(int cost,int weight)
{
    for(int i=total;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+weight);
}
void complete(int cost,int weight)
{
    for(int i=cost;i<=cost;i++) dp[i]=max(dp[i],dp[i-cost]+weight);
}
void multi(int cost,int weight,int cnt)
{
    if(total<=cnt*cost)
    {
        complete(cost,weight);
        return;
    }
    int k=1;
    while(k<=cnt)
    {
        zero(k*cnt,k*weight);
        cnt=cnt-k;
        k=2*k;
    }
    zero(cnt*cost,cnt*weight);
}
int main()
{
    while(~scanf("%d",&n))
    {
        if(n==-1) break;
        total=0;
        sum=0;
        for(int i=0;i<n;i++) {
            scanf("%d%d",&value[i],&num[i]);
            total+=(value[i]*num[i]);
        }
        printf("%d \n",total);
        sum=total;
        total/=2;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            multi(value[i],value[i],num[i]);
        }
        printf("%d %d\n",sum-dp[total],dp[total]);
    }
    return 0;
}  

也可以用01背包搞 就是把相同价值的一种看成是多件

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,tot,a,b,sum;
    int dp[255000],val[600];
    int main()
    {
        while(~scanf("%d",&n),n>0)
        {
            sum=0;
            tot=0;
            for(int i=0;i<n;i++)
            {
                scanf("%d%d",&a,&b);
                while(b--)
                {
                    val[tot++]=a;
                    sum+=a;
                }
            }
            memset(dp,0,sizeof(dp));
            for(int i=0;i<tot;i++)
            {
                for(int j=sum/2;j>=val[i];j--)
                {
                    dp[j]=max(dp[j],dp[j-val[i]]+val[i]);
                }
            }
            printf("%d %d\n",sum-dp[sum/2],dp[sum/2]);
        }
        return 0;
    }  

7.  01背包求第k优解

hdu2639bone collector II【第K优解】

作为一个正常的背包,我们必须做的两重循环是一定要写的,接下来就是维护最优解到第k优解的的数组。个人觉得这个题最最值得学习的就是维护数组的写法:

首先每次想加入新物品的时候,正常来说我们有两个值:之前的dp和加入新物品时的值,然而我们现在也需要考虑第k优解的问题,所以用两个临时的数组倒一下,再用这两个数组合并到一起存储到最终的dp数组中

    /************
    hdu2639
    2015.10.20
    109MS 5548K 1226B
    ************/
    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int dp[1009][1009];
    int value[109],cost[109];
    int n,k,v,t;
    int a[1009],b[1009];
    int main()
    {
        while(~scanf("%d",&t))
        {
            while(t--)
            {
                scanf("%d%d%d",&n,&v,&k);
                for(int i=1;i<=n;i++) scanf("%d",&value[i]);
                for(int i=1;i<=n;i++) scanf("%d",&cost[i]);
                memset(dp,0,sizeof(dp));
                for(int i=1;i<=n;i++)
                    for(int j=v;j>=cost[i];j--)
                    {
                        for(int m=1;m<=k;m++)
                        {
                            a[m]=dp[j][m];
                            b[m]=dp[j-cost[i]][m]+value[i];
                        }
                        int x=1,y=1,w=1;
                        a[k+1]=-1;b[k+1]=-1;
                        while((w<=k)&&(x<=k||y<=k))
                        {
                            if(a[x]<b[y]) dp[j][w]=b[y++];
                            else dp[j][w]=a[x++];
                            if(w==1||dp[j][w-1]!=dp[j][w]) w++;
                        }
                    }
                printf("%d\n",dp[v][k]);
            }
        }
        return 0;
    }  

8.

hdu3466Proud Merchants【至少需要Qi才能买Pi】

hdu5188zhx and contest [01背包至少li才能。。。]

他俩是一类问题,只是表述有区别而已:手头的钱数大于等于Qi才可以放当前商品,后一个题由于没有明显的给上限,所以手动维护一个sum是所占体积和与至少需要体积最大值这两个数中最大值。有必要说一下排序函数的由来,设A:p1,q1 B:p2,q2,如果先A后B,则至少需要p1+q2的容量,如果先B后A,至少需要p2+q1的容量,那么就是p1+q2 > p2+q1,变形之后就是q1-p1 < q2-p2。

    #include<stdio.h>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int MAXN=5005;
    int dp[MAXN];
    struct Node
    {
        int p,q,v;
    }node[505];
    bool cmp(Node a,Node b)
    {
        return  (a.q-a.p)<(b.q-b.p);
    }
    int main()
    {
        int n,m;
        int i,j;
        int p,q,v;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(i=0;i<=m;i++)
              dp[i]=0;
            for(i=0;i<n;i++)
            {
                scanf("%d%d%d",&node[i].p,&node[i].q,&node[i].v);
            }
            sort(node,node+n,cmp);
            for(i=0;i<n;i++)
            {
                for(j=m;j>=node[i].p;j--)
                {
                    if(j>=node[i].q)
                      dp[j]=max(dp[j],dp[j-node[i].p]+node[i].v);
                }
            }
            int ans=0;
            for(i=1;i<=m;i++)
              if(ans<dp[i])  ans=dp[i];
            printf("%d\n",ans);  

        }
        return 0;
    }
        #include<stdio.h>
        #include<algorithm>
        #include<iostream>
        #include<cstring>
        using namespace std;
        const int MAXN=4000009;
        int dp[MAXN];
        struct Node
        {
            int p,q,v;
        }node[35];
        bool cmp(Node a,Node b)
        {
            return  (a.q-a.p)<(b.q-b.p);
        }
        int main()
        {
           // freopen("cin.txt","r",stdin);
            int n,w;
            int i,j;
            int p,q,v;
            while(scanf("%d%d",&n,&w)!=EOF)
            {
                memset(dp,0,sizeof(dp));
                int sum=0,up=0;
                for(i=0;i<n;i++)
                {
                    scanf("%d%d%d",&node[i].p,&node[i].v,&node[i].q);
                    sum+=node[i].p;
                    up=max(up,node[i].q);
                }
                up=max(up,sum);
                sort(node,node+n,cmp);
                for(i=0;i<n;i++)
                {
                    for(j=up;j>=node[i].p;j--)
                    {
                        if(j>=node[i].q)
                          dp[j]=max(dp[j],dp[j-node[i].p]+node[i].v);
                    }
                }
                int ans=0;
                for(i=1;i<=up;i++)
                  if(w<=dp[i])  {ans=i;break;}
                if(ans) printf("%d\n",ans);
                else puts("zhx is naive!");
            }
            return 0;
        }  

<span style="font-size:14px;">
</span>

9.负数处理+两个总和的和最大

poj2184Cow Exhibition【01背包 负数】

题意:每只奶牛都有一个聪明值和有趣值,最终想求得选取一些奶牛使得这两个的总和最大,而且聪明值的和与有趣值的总和分别都不能为负

虽然N只有100,但是也不可以逐个枚举啊,可以选取两个值中的一个作为背包容量,另一个作为总价值。负数的处理是另外与价值数组更新时维护一个数组表示当前数组内的元素,因为+1000了嘛,要记着加了几个。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <map>
#define LL long long  

using namespace std;  

const int N = 110;
const int M = 200010;
const int NN = 1000;
const int INF = 10000000;
int w[N],v[N],sum;
int dp[M], cnt[M];
int main()
{
   // freopen("1.txt","r",stdin);
    int n;
    while(~scanf("%d",&n))
    {
        sum=0;
        for(int i=1;i<=n;i++) {
            scanf("%d%d",&v[i],&w[i]);
            if(v[i]<0&&w[i]<0){i--,n--;continue;}
            v[i]+=1000;
            sum+=v[i];
        }
        memset(dp,-0x3f3f3f3f,sizeof(dp));
        dp[0]=0;
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=n;i++)
        {
            for(int j=sum;j>=v[i];j--)
            {
                if(dp[j-v[i]]+w[i]-(cnt[j-v[i]]+1)*1000>dp[j]-cnt[j]*1000)
                {
                    cnt[j]=cnt[j-v[i]]+1;
                    dp[j]=dp[j-v[i]]+w[i];
                }
            }
        }
        int ans=0;
        for(int i=0;i<=sum;i++)
        {
            if(i-cnt[i]*1000>0&&dp[i]>0)//
            {
                ans=max(ans,dp[i]-cnt[i]*1000+i);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}  

10.

hdu2159FATE【二维完全背包】

xhd升掉最后一级还需n的经验值,xhd还留有m的忍耐度,每杀一个怪xhd会得到相应的经验,并减掉相应的忍耐度。当忍耐度降到0或者0以下时,xhd就不会玩这游戏。xhd还说了他最多只杀s只怪。请问他能升掉这最后一级吗?

既然是二维背包那么二维分别是现有忍耐度和打怪的个数

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[105][105],k,n,m,s,a[105],b[105];
int main()
{
 //   freopen("cin.txt","r",stdin);
    while(~scanf("%d%d%d%d",&n,&m,&k,&s))
    {
        for(int i=1;i<=k;i++) scanf("%d%d",&a[i],&b[i]);
       // memset(f,0,sizeof(f));
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=k;i++)
        {
            for(int j=b[i];j<=m;j++)
            {
                for(int l=1;l<=s;l++)
                {
                    dp[j][l]=max(dp[j][l],dp[j-b[i]][l-1]+a[i]);
                }
            }
        }
        int flag=0;
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=s;j++)
            {
                if(dp[i][j]>=n)
                {
                    printf("%d\n",m-i);
                    flag=1;
                    goto loop;
                }
            }
        }
        loop :
        if(!flag) printf("-1\n");
    }
    return 0;
}  

11.二维完全背包分面积,给出小块区域的价值,求最大值

hdu3127WHUgirls【二维完全背包】

啥都不说,直接上图==

    /*************
    hdu3127
    2015.10.27-2015.10.29
    296MS 5536K 1130 B
    ************/
    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,X,Y,t;
    int dp[1005][1005],x[12],y[12],c[12];
    int max(int a,int b,int c)
    {
        if(a>b)
        {
            if(c>a) return c;
            return a;
        }
        if(c>b) return c;
        return b;
    }
    int main()
    {
        //freopen("cin.txt","r",stdin);
        cin>>t;
        while(t--)
        {
            cin>>n>>X>>Y;
            for(int i=1;i<=n;i++) cin>>x[i]>>y[i]>>c[i];
            memset(dp,0,sizeof(dp));
            for(int k=1;k<=n;k++)
            {
                for(int i=0;i<=X;i++)
                {
                    for(int j=0;j<=Y;j++)
                    {  

                        if(i>=x[k]&&j>=y[k])
                        dp[i][j]=max(dp[i][j],dp[i-x[k]][j]+dp[x[k]][j-y[k]]+c[k],dp[i][j-y[k]]+dp[i-x[k]][y[k]]+c[k]);
                        if(i>=y[k]&&j>=x[k])
                        dp[i][j]=max(dp[i][j],dp[i-y[k]][j]+dp[y[k]][j-x[k]]+c[k],dp[i][j-x[k]]+dp[i-y[k]][x[k]]+c[k]);
                    }
                }
            }
            cout<<dp[X][Y]<<endl;
        }
        return 0;
    }  

12.

hdu1248寒冰王座【完全背包入门题】

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int dp[10005],t,n;
    int value[4]={0,150,200,350};
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            for(int i=1;i<=n;i++) dp[i]=0;
            for(int i=1;i<=3;i++)
                for(int j=value[i];j<=n;j++)
                {
                    dp[j]=max(dp[j-value[i]]+value[i],dp[j]);
                }
            printf("%d\n",n-dp[n]);
        }
        return 0;
    }  

13.

hdu2191悼念512汶川大地震遇难同胞——珍惜现在,感恩生活【多重背包模板题】

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[1050],c[1050],w[1050],m[1050];
int n,M,t;
void zeropack(int cost,int weight)
{
    for(int i=n;i>=cost;i--)
        dp[i]=max(dp[i-cost]+weight,dp[i]);
}
void completepack(int cost,int weight)
{
    for(int i=cost;i<=n;i++)
        dp[i]=max(dp[i-cost]+weight,dp[i]);
}
void multipack(int cost,int weight,int num)
{
    if(num*cost>=n)
    {
        completepack(cost,weight);
        return;
    }
    int k=1;
    while(k<num)
    {
        zeropack(k*cost,k*weight);
        num-=k;
        k*=2;
    }
    zeropack(cost*num,weight*num);
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&M);
        for(int i=1;i<=M;i++) scanf("%d%d%d",&c[i],&w[i],&m[i]);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=M;i++)
        {
            multipack(c[i],w[i],m[i]);
        }
        printf("%d\n",dp[n]);
    }
    return 0;
} 

14.求一共可以凑出的方法数

hdu2844Coins【多重背包】

因为体积和价值是同一个数,那么dp值很容易想到就是1-max遍历值==i的总数++

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int dp[100007],n,m,a[105],c[105],count;
    void zeropack(int cost,int value)
    {
        for(int i=m;i>=cost;i--)
            dp[i]=max(dp[i],dp[i-cost]+value);
       // cout<<"01"<<endl;
    }
    void completepack(int cost,int value)
    {
        for(int i=cost;i<=m;i++)
            dp[i]=max(dp[i],dp[i-cost]+value);
        //cout<<"complete"<<endl;
    }
    void multipack(int cost,int value,int num)
    {
        if(num*cost>=m)
        {
            completepack(cost,value);
            return;
        }
        int k=1;
        while(k<num)
        {
            zeropack(k*cost,k*value);
            num-=k;
            k*=2;
        }
        zeropack(num*cost,num*value);
    }
    int main()
    {
       // freopen("cin.txt","r",stdin);
        while(~scanf("%d%d",&n,&m))
        {
            if(n==0&&m==0) break;
            for(int i=1;i<=n;i++) scanf("%d",&a[i]);
            for(int i=1;i<=n;i++) scanf("%d",&c[i]);
            memset(dp,0,sizeof(dp));
            count=0;
            for(int i=1;i<=n;i++)
            {
                multipack(a[i],a[i],c[i]);
            }  

            for(int i=1;i<=m;i++)
            {
                if(dp[i]==i) count++;
                //printf("dp[]=%d\n",dp[i]);
            }
            printf("%d\n",count);
        }
        return 0;
    }  

15.多重背包模板题

hdu1059Dividing【多重背包】

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[90000],value[10],cost[10],num[10],v;
void zeropack(int cost,int value)
{
    for(int i=v;i>=cost;i--)
        dp[i]=max(dp[i],dp[i-cost]+value);
   // printf("zero   ");
}
void complete(int cost,int value)
{
    for(int i=cost;i<=v;i++)
        dp[i]=max(dp[i],dp[i-cost]+value);
    //printf("complete    ");
}
void multipack(int cost,int value,int num)
{
    if(num==0) return;
    if(cost*num>=v)
    {
        complete(cost,value);
        return;
    }
    int k=1;
    while(k<num)
    {
        zeropack(k*cost,k*value);
        num-=k;
        k*=2;
    }
    zeropack(num*cost,num*value);
}
int main()
{
    //freopen("cin.txt","r",stdin);  

    int cnt=1;
    while(~scanf("%d%d%d%d%d%d",&num[1],&num[2],&num[3],&num[4],&num[5],&num[6]))
    {
        for(int i=1;i<=6;i++) value[i]=i;
        for(int i=1;i<=6;i++) cost[i]=i;
        if(num[1]==0&&num[2]==0&&num[3]==0&&num[4]==0&&num[5]==0&&num[6]==0) break;
        v=num[1]+num[2]*2+num[3]*3+num[4]*4+num[5]*5+num[6]*6;
        //for(int i=1;i<=6;i++) if(!num[i]) {value[i]=0;cost[i]=0;}
        //for(int i=1;i<=6;i++) printf("%d   ",num[i]);
        if(v&1)
        {
            printf("Collection #%d:\nCan't be divided.\n\n",cnt++);
            continue;
        }
        v/=2;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=6;i++)
        {
            if(num[i]==0) continue;
            //printf("i=%d  ",i);
            multipack(cost[i],value[i],num[i]);
           // printf("i=%d    ",i);
           // for(int j=cost[i];j<=v;j++)printf("i=%d j=%d  dp[j]=%d      ",i,j,dp[j]);
          // printf("\n");
        }
        //printf("%d\n",dp[v]);
       // for(int i=1;i<=6;i++) printf("%d  ",dp[i]);
        if(dp[v]!=v)
            printf("Collection #%d:\nCan't be divided.\n\n",cnt++);
        else
            printf("Collection #%d:\nCan be divided.\n\n",cnt++);
    }
    return 0;
}  

16.给钱加找钱最少个数和

hdu3591The trouble of Xiaoqian【多重背包】

由于手里的各种钱个数有限,所以多重背包跑一遍,注意每个dp的下标都是实际可以达到的!再给找的钱跑一遍完全背包,两个循环找最小值和

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 20000
int dp1[maxn+6],value[105],num[105],t,n,dp2[maxn+6];//钱币个数
int f1[maxn+6],f2[maxn+6];//钱数
void zeropack(int cost,int value,int k)
{
    for(int i=maxn;i>=cost;i--)
    {
        if(dp1[i-cost]!=-1&&(dp1[i-cost]+k<dp1[i]||dp1[i]==-1))
        dp1[i]=dp1[i-cost]+k;
    }
   // cout<<"01"<<endl;
}
void completepack(int cost,int value)
{
    for(int i=cost;i<=maxn;i++)
    {
        if(dp1[i-cost]!=-1&&(dp1[i-cost]+1<dp1[i]||dp1[i]==-1))
        dp1[i]=dp1[i-cost]+1;
       // f1[i]=max(f1[i],f1[i-cost]+value);
    }
    //cout<<"complete"<<endl;
}
void multipack(int cost,int value,int num)
{
    if(num*cost>=maxn)
    {
        completepack(cost,value);
        return;
    }
    int k=1;
    while(k<num)
    {
        zeropack(k*cost,k*value,k);
        num-=k;
        k*=2;
    }
    zeropack(num*cost,num*value,k);
}
int main()
{
   // freopen("cin.txt","r",stdin);
    int cnt=1;
    while(~scanf("%d%d",&n,&t))
    {
        if(t==0&&n==0) break;
        for(int i=1;i<=n;i++) scanf("%d",&value[i]);
        for(int i=1;i<=n;i++) scanf("%d",&num[i]);
        memset(dp2,-1,sizeof(dp2));
        memset(dp1,-1,sizeof(dp1));
        memset(f1,0,sizeof(f1));
        memset(f2,0,sizeof(f2));
        dp2[0]=0;dp1[0]=0;
        for(int i=1;i<=n;i++)
            for(int j=value[i];j<=maxn;j++)
            {
                if(dp2[j-value[i]]!=-1&&(dp2[j]<dp2[j-value[i]]+1||dp2[j]==-1))
                dp2[j]=dp2[j-value[i]]+1;
               // f2[j]=max(f2[j],f2[j-value[i]]+value[i]);
            }
        for(int i=1;i<=n;i++)
        {
            multipack(value[i],value[i],num[i]);
        }
       // for(int i=70;i<=80;i++) printf("f1=%d f2=%d dp1=%d dp2=%d\n",f1[i],f2[i],dp1[i],dp2[i]);
        int minn=0x3f3f3f3f;
        for(int i=t;i<=maxn;i++)
        {
            //if(f1[i]!=i||f2[i-t]!=i-t) continue;
            if(dp1[i]!=-1&&dp2[i-t]!=-1)
            minn=min(minn,dp1[i]+dp2[i-t]);
        }
        if(minn!=0x3f3f3f3f)
        printf("Case %d: %d\n",cnt++,minn);
        else printf("Case %d: -1\n",cnt++);
    }
    return 0;
}  

17.

hdu3535AreYouBusy【分组背包综合题】

这是一道综合性的背包问题。题目给出了多组工作,每组工作的选择规则不同,有些组至少要选一项,有些组最多选一项,有些组任意选。
  这道题花了很长时间,需要深入理解状态转移才能够明白。数组dp[i][j],表示第i组,时间剩余为j时的快乐值。每得到一组工作就进行一次DP,所以dp[i]为第i组的结果。下面对三种情况进行讨论。
  第一类,至少选一项,即必须要选,那么在开始时,对于这一组的dp的初值,应该全部赋为负无穷,这样才能保证不会出现都不选的情况。状态转移方程为dp[i][k]=max{ dp[i][k],dp[i-1][k-cost[j]]+val[k],dp[i][k-cost[j]]+val[j] }。dp[i][k]是不选择当前工作;dp[i-1][k-cost[j]]+val[k]是选择当前工作,但是是第一次在本组中选,由于开始将该组dp赋为了负无穷,所以第一次取时,必须由上一组的结果推知,这样才能保证得到全局最优解;dp[i][k-cost[j]]+val[j]表示选择当前工作,并且不是第一次取。
  第二类,最多选一项,即要么不选,一旦选,只能是第一次选。所以状态转移方程为dp[i][k]=max{ dp[i][k],dp[i-1][k-cost[j]]+val[k]}。由于要保证得到全局最优解,所以在该组DP开始以前,应该将上一组的DP结果先复制到这一组的dp[i]数组里,因为这一组的数据是在上一组数据的基础上进行更新的。
  第三类,任意选,即不论选不选,选几次都可以,显然状态转移方程为dp[i][k]=max{ dp[i][k],dp[i-1][k-cost[j]]+val[k],dp[i][k-cost[j]]+val[j] }。同样要保证为得到全局最优解,先复制上一组解。
    #include<stdio.h>
    #include<string.h>
    #define INF 1000000
    #define MAX_LIMT 110
    int get_max(int,int);
    int main()
    {
        int n,t;
        while(scanf("%d%d",&n,&t)!=EOF)
        {
        int i,j,k,dp[MAX_LIMT][MAX_LIMT];
        memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++)
        {
            int m,s,cost[MAX_LIMT],val[MAX_LIMT];
            scanf("%d%d",&m,&s);
            for(j=1;j<=m;j++)
            {
                scanf("%d%d",&cost[j],&val[j]);
            }
            if(s==0)
            {
                for(j=0;j<=t;j++)
                {
                    dp[i][j]=-INF;
                }
                for(j=1;j<=m;j++)
                {
                    for(k=t;k>=cost[j];k--)
                    {
                        dp[i][k]=get_max( dp[i][k],dp[i][k-cost[j]]+val[j]);
                        dp[i][k]=get_max( dp[i][k],dp[i-1][k-cost[j]]+val[j]);
                    }
                }
            }
            else if(s==1)
            {
                for(j=0;j<=t;j++)
                {
                    dp[i][j]=dp[i-1][j];
                }
                for(j=1;j<=m;j++)
                {
                    for(k=t;k>=cost[j];k--)
                    {
                        dp[i][k]=get_max(dp[i][k],dp[i-1][k-cost[j]]+val[j]);
                    }
                }
            }
            else
            {
                for(j=0;j<=t;j++)
                {
                    dp[i][j]=dp[i-1][j];
                }
                for(j=1;j<=m;j++)
                {
                    for(k=t;k>=cost[j];k--)
                    {
                        dp[i][k]=get_max( dp[i][k],dp[i][k-cost[j]]+val[j]);
                        dp[i][k]=get_max( dp[i][k],dp[i-1][k-cost[j]]+val[j]);
                    }
                }
            }
        }
        dp[n][t]=get_max(dp[n][t],-1);
        printf("%d\n",dp[n][t]);
        }
        return 0;
    }
    int get_max(int x,int y)
    {
        return x>y?x:y;
    }  

18.2012 Multi-University Training Contest 9

hdu4381Grid【微复杂的背包】

1 ai xi :You can choose any xi black boxes in interval [1,ai], and color them white;

2 ai xi :You can choose any xi black boxes in interval [ai,n], and color them white;

求最终能有最多多少白色格子。

由于题中没说到底涂哪些,我们认为都是连着涂的,那么我们就可以将给出的数据转化成可涂的长度,分别用两个数组计算当前长度范围最多可涂个数的最少次数,求和取最小值即可

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <vector>
    #include <cmath>  

    using namespace std;
    const int maxn = 2005;
    struct node{
        int aa,cor;
        node(){}
        node(int _aa,int _cor){
           aa = _aa;   cor = _cor;
        }
    }x1[maxn],x2[maxn];
    int n,m;
    int dp1[maxn],dp2[maxn];
    int sumx1,sumx2;  

    bool cmp(const node &p,const node &q){
        return p.aa < q.aa;
    }  

    int min(int a,int b)
    {
        return a<b?a:b;
    }  

    int main()
    {
        int cas,ta=1;
        scanf("%d",&cas);
        while(cas--){
             int i,j;
             scanf("%d%d",&n,&m);  

             sumx1 = sumx2 = 1;
             for(i=0; i<m; i++){
                 int key,yy,z;
                 scanf("%d%d%d",&key,&yy,&z);
                 if(key == 1){
                    x1[sumx1++] = node(yy,z);
                 }else{
                    x2[sumx2++] = node(n+1-yy,z);
                 }
             }
             sort(x1+1,x1+sumx1,cmp);
             sort(x2+1,x2+sumx2,cmp);
             memset(dp1,0x3f,sizeof(dp1));
             memset(dp2,0x3f,sizeof(dp2));  

             dp1[0] = dp2[0] = 0;
             for(i=1; i<sumx1; i++){
                 for(j=x1[i].aa; j>=x1[i].cor; j--){
                    dp1[j] = min(dp1[j],dp1[j-x1[i].cor]+1);
                 }
             }  

             for(i=1; i<sumx2; i++){
                 for(j=x2[i].aa; j>=x2[i].cor; j--){
                    dp2[j] = min(dp2[j],dp2[j-x2[i].cor]+1);
                 }
             }  

             int ans = 0,anssum = 0,tmp;
             for(i=1; i<=n; i++){
                for(j=0; j<=i; j++){
                   tmp = dp1[j] + dp2[i-j];
                   if(tmp <= m){
                      if(ans != i){
                        ans = i;   anssum = tmp;
                      }else if(tmp < anssum){
                          anssum = tmp;
                      }
                   }
                }
             }  

             printf("Case %d: %d %d\n",ta++,ans,anssum);
        }
        return 0;
    }  

19。多重背包至多ai才可以放

poj2392Space Elevator【多重背包】

和“至少”的情况一样,都要先排序

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int dp[40004];
    int n,M,t;
    struct node
    {
        int cost,weight,num,height;
    }num[300];
    bool cmp(node a,node b)
    {
        return a.height<b.height;
    }
    void zeropack(int cost,int weight,int height)
    {
        for(int i=height;i>=cost;i--)
            dp[i]=max(dp[i-cost]+weight,dp[i]);
    }
    void completepack(int cost,int weight,int height)
    {
        for(int i=cost;i<=height;i++)
            dp[i]=max(dp[i-cost]+weight,dp[i]);
    }
    void multipack(int cost,int weight,int num,int height)
    {
        if(num*cost>=height)
        {
            completepack(cost,weight,height);
            return;
        }
        int k=1;
        while(k<num)
        {
            zeropack(k*cost,k*weight,height);
            num-=k;
            k*=2;
        }
        zeropack(cost*num,weight*num,height);
    }
    int main()
    {
      //  freopen("cin.txt","r",stdin);
        while(~scanf("%d",&n))
        {
            int maxn=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d%d",&num[i].cost,&num[i].height,&num[i].num);
                num[i].weight=num[i].cost;
                if(maxn<num[i].height) maxn=num[i].height;
            }
            sort(num+1,num+1+n,cmp);
         //   printf("hei=%d   ",maxn);
            memset(dp,0,sizeof(dp));
             for(int i=1;i<=n;i++) multipack(num[i].cost,num[i].weight,num[i].num,num[i].height);
             int tmp=0;
             for(int i=1;i<=maxn;i++)
             {
                 if(tmp<dp[i]) tmp=dp[i];
                //printf("%d  ",dp[i]);
             }
            printf("%d\n",tmp);
        }
        return 0;
    }  

20.

hdu1712ACboy needs your help【分组背包入门题】

第一层是不同科间的循环,第二层的循环是v从已知最大天数到0,第三层是组内循环也就是每个课程选几天的付出

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int num[110][110],n,m;
int dp[110];
int max(int a,int b){if(a>b)return a;return b;}
int main()
{
   // freopen("cin.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        if(m==0&&n==0)break;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&num[i][j]);
        memset(dp,0,sizeof(dp));
        for(int k=1;k<=n;k++)//the type of course
            for(int v=m;v>=0;v--)
                for(int j=1;j<=v;j++)
                    dp[v]=max(dp[v],dp[v-j]+num[k][j]);
        printf("%d\n",dp[m]);
    }
    return 0;
}  

21.分组背包每组至少去取一个

由于限制了每组个数,我们需要加一维表示组别,而且前一状态不可没被填充

hdu3033I love sneakers!【分组背包】每组至少取一个

    /***********
    hdu3033
    2016.3.13
    93MS    5888K   1238B   G++
    ***********/
    #include <iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    struct node
    {
        int u,v;
    }g[15][110];
    int num[15],dp[110][10005];
    int n,m,k,a,b,c;
    int max(int a,int b){if(a>b)return a;return b;}
    #define inf  0x3f3f3f3f
    int main()
    {
        while(~scanf("%d%d%d",&n,&m,&k))
        {
            memset(num,0,sizeof(num));
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d%d",&a,&b,&c);
                num[a]++;
                g[a][num[a]].u=b;
                g[a][num[a]].v=c;
            }
            memset(dp,-inf,sizeof(dp));  //有的时候memset赋值-inf会出错
            memset(dp[0],0,sizeof(dp[0]));
            for(int i=1;i<=k;i++)
            {
                for(int j=1;j<=num[i];j++)
                {
                    for(int v=m;v>=g[i][j].u;v--)
                    {
                        //if(dp[i][v-g[i][j].u]!=-1)
                        dp[i][v]=max(dp[i][v],dp[i][v-g[i][j].u]+g[i][j].v);
                        //if(dp[i-1][v-g[i][j].u]!=-1)
                        dp[i][v]=max(dp[i][v],dp[i-1][v-g[i][j].u]+g[i][j].v);
                    }
                }
            }
            if(dp[k][m]<0)printf("Impossible\n");
            else printf("%d\n",dp[k][m]);
        }
        return 0;
    }  

22.

hdu3469Watch The Movie【分组背包】二维dp数组

小姑娘开学前晚上看电影只能L分钟,有N个不同的电影可以选择,傲娇老板只恰好卖M张蝶,给出每部电影时长和快乐值,问最大的快乐值是多少

组别是n种电影,组内是电影的个数,dp一维表示电影个数,二维表示时间长度

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define inf 0x3f3f3f3f
    int dp[102][1005],cost[102],value[102],t,n,m,l;
    int max(int a,int b){if(a>b)return a;return b;}
    int main()
    {
       // freopen("cin.txt","r",stdin);
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d%d",&n,&m,&l);
            for(int i=1;i<=n;i++)scanf("%d%d",&cost[i],&value[i]);
            for(int i=0;i<=m;i++)
                for(int j=0;j<=l;j++)
                    dp[i][j]=-0x3f3f3f3f;
            dp[m][l]=dp[0][0]=0;
            for(int i=1;i<=n;i++)
                for(int j=m;j>0;j--)
                    for(int k=cost[i];k<=l;k++)
                        dp[j][k]=max(dp[j][k],dp[j-1][k-cost[i]]+value[i]);//printf("i=%d,j=%d,k=%d,dp=%d\n",i,j,k,dp[j][k]);
            for(int i=0;i<l;i++)dp[m][l]=max(dp[m][l],dp[m][i]) ;
            printf("%d\n",dp[m][l]);
        }
        return 0;
    }  

23.01背包方法数使得是剩下的钱数不能大于没买的物品的最小值

poj3093Margaritas on the River Walk【01背包计算方法数】

//思路:先对n个体积进行从小到大的排序,然后枚举i作为剩余物品中体积最小为v,dp[j]为方案数(其中j为当前体积).那么可以分析对于大于i的,
//很显然是可以放进背包的,又因为i为剩余的物品,所以不放进去;对于大于i的物品则进行背包的可行方案的统计.然后计算{Fn[j]}之和。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define M 10000
#define max(a, b) (a > b ? a : b)

int data[M], dp[M];
int n, c;

int cmp(const void *a, const void *b)
{
	return *(int *)a - *(int *)b;
}

int main()
{
	//freopen("1.txt", "r", stdin);
	int i, j, k, test, sum, ans, num = 1;

	scanf("%d", &test);
	while (test--)
	{
		scanf("%d%d", &n, &c);
		for (i = 1; i <= n; i++)
		{
			scanf("%d", &data[i]);
		}
 		qsort(data + 1, n, sizeof(data[1]), cmp);
		memset(dp, 0, sizeof(dp));
		for (i = 1, sum = 0, ans = 0; i <= n; i++)
		{
			memset(dp, 0, sizeof(dp));
			dp[sum] = 1;
			for (j = i + 1; j <= n; j++)
			{
				for (k = c; k >= data[j] + sum; k--)
				{
					dp[k] += dp[k - data[j]];
				}
			}
			for (j = c; j >= max(c - data[i] + 1, 1); j--)  //c-data[i]+1 其中+1是因为下标以1开始
			{
				if (j >= sum)
				{
					ans += dp[j];
				}
			}
			sum += data[i];
		}
		printf("%d %d\n", num++, ans);
	}

	return 0;
}

24.

hdu3236Gift Hunting【二维01背包】

题意:给女朋友买一堆礼物,每个礼物有一个快乐值,有n个备选的,其中有一部分是必买的,总共有两张支票,价值v1,v2,花钱少了不给退,两张支票不能凑在一起用,而且有一个礼物是免费的,问女友最多可以多快乐?

做法:这个题的处理方法是再加一维dp表示是否用过这个免费的机会(貌似之前树形dp做过吧)之后,dp转移是很容易可以想到的==

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int cost1[309],hap1[309],cost0[309],hap0[309],dp[505][55][2],n,v1,v2;
    int main()
    {
       // freopen("cin.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int cas=1;
        while(~scanf("%d%d%d",&v1,&v2,&n))
        {
            if(v1==0&&v2==0&&n==0)break;
            memset(dp,0,sizeof(dp));
            int l0=0,l1=0,maxh=0,maxn;
            for(int i=0;i<n;i++)
            {
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                if(c==1)
                {
                    cost1[l1]=a;
                    hap1[l1++]=b;
                    maxh+=b;
                }
                if(c==0)
                {
                    cost0[l0]=a;
                    hap0[l0++]=b;
                }
            }
            for(int i=0;i<l1;i++)
            {
                for(int j=v1;j>=0;j--)
                {
                    for(int k=v2;k>=0;k--)
                    {
                        dp[j][k][1]=max(dp[j][k][1],dp[j][k][0]+hap1[i]);
                        if(j>=cost1[i])
                            dp[j][k][0]=max(dp[j][k][0],dp[j-cost1[i]][k][0]+hap1[i]),
                            dp[j][k][1]=max(dp[j][k][1],dp[j-cost1[i]][k][1]+hap1[i]);
                        if(k>=cost1[i])
                            dp[j][k][0]=max(dp[j][k][0],dp[j][k-cost1[i]][0]+hap1[i]),
                            dp[j][k][1]=max(dp[j][k][1],dp[j][k-cost1[i]][1]+hap1[i]);
                   //     printf("i=%d,j=%d,k=%d,dp0=%d,dp1=%d\n",i,j,k,dp[j][k][0],dp[j][k][1]);
                    }
                }
            }
            if(dp[v1][v2][1]<maxh)maxn=-1;
            else
            {
                for(int i=0;i<l0;i++)
                {
                    for(int j=v1;j>=0;j--)
                    {
                        for(int k=v2;k>=0;k--)
                        {
                            if(dp[j][k][0]>=maxh)
                                dp[j][k][1]=max(dp[j][k][1],dp[j][k][0]+hap0[i]);
                            if(j>=cost0[i]&&dp[j-cost0[i]][k][0]>=maxh)
                                dp[j][k][0]=max(dp[j][k][0],dp[j-cost0[i]][k][0]+hap0[i]);
                            if(j>=cost0[i]&&dp[j-cost0[i]][k][1]>=maxh)
                                dp[j][k][1]=max(dp[j][k][1],dp[j-cost0[i]][k][1]+hap0[i]);
                            if(k>=cost0[i]&&dp[j][k-cost0[i]][0]>=maxh)
                                dp[j][k][0]=max(dp[j][k][0],dp[j][k-cost0[i]][0]+hap0[i]);
                            if(k>=cost0[i]&&dp[j][k-cost0[i]][1]>=maxh)
                                dp[j][k][1]=max(dp[j][k][1],dp[j][k-cost0[i]][1]+hap0[i]);
                        //    printf("i=%d,j=%d,k=%d,dp0=%d,dp1=%d\n",i,j,k,dp[j][k][0],dp[j][k][1]);
                        }
                    }
                }
                maxn=dp[v1][v2][1];
            }
            printf("Case %d: %d\n\n",cas++,maxn);
        }
        return 0;
    }

25.

poj1276Cash Machine【多重背包模板题】

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int dp[100009],c[100009],w[100009],m[100009];
    int n,M,t;
    void zeropack(int cost,int weight)
    {
        for(int i=M;i>=cost;i--)
            dp[i]=max(dp[i-cost]+weight,dp[i]);
    }
    void completepack(int cost,int weight)
    {
        for(int i=cost;i<=M;i++)
            dp[i]=max(dp[i-cost]+weight,dp[i]);
    }
    void multipack(int cost,int weight,int num)
    {
        if(num*cost>=M)
        {
            completepack(cost,weight);
            return;
        }
        int k=1;
        while(k<num)
        {
            zeropack(k*cost,k*weight);
            num-=k;
            k*=2;
        }  

        zeropack(cost*num,weight*num);
    }
    int main()
    {
        //freopen("cin.txt","r",stdin);
        while(~scanf("%d%d",&M,&n))
        {
            for(int i=1;i<=n;i++){scanf("%d%d",&m[i],&c[i]);w[i]=c[i];}
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++)
            {
                multipack(c[i],w[i],m[i]);
            }
            printf("%d\n",dp[M]);
        }
        return 0;
    }

26.

poj1837Balance【二维01背包方法数——天平平衡】

题意:已知砝码(都只有一个)和天平左右挂钩的位置,问有多少种使得天平平衡的方法

做法:很需要那维表示当前物品序号,因为转移方程是dp[i][j]+=dp[i-1][j-pos[k]*weight[i]];

负数的处理,十分纠结于7500是中间值,要是没到这么大的话怎么办啊==看代码

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int dp[30][20009];
    int c,g,pos[30],weight[30];
    int main()
    {
       // freopen("cin.txt","r",stdin);
       // freopen("out.txt","w",stdout);
        while(~scanf("%d%d",&c,&g))
        {
            for(int i=1;i<=c;i++)
            {
                scanf("%d",&pos[i]);
                //cc[i]+=15;
            }
            for(int i=1;i<=g;i++)scanf("%d",&weight[i]);
            memset(dp,0,sizeof(dp));
            dp[0][10000]=1;
            int maxn=20000;
            for(int i=1;i<=g;i++)
                for(int j=0;j<=maxn;j++)
                    for(int k=1;k<=c;k++)
                        if(j>=pos[k]*weight[i])
                        {
                            dp[i][j]+=dp[i-1][j-pos[k]*weight[i]];
                          //  printf("i=%d,j=%d,k=%d,dp=%d\n",i,j,k,dp[i][j]);
                        }  

            printf("%d\n",dp[g][10000]);
        }
        return 0;
    }  
时间: 2024-10-12 04:22:18

背包问题总结篇的相关文章

【动态规划】多重背包问题

说明 前面已经介绍完了01背包和完全背包,今天介绍最后一种背包问题--多重背包. 这个背包,听起来就很麻烦的样子.别慌,只要你理解了前面的两种背包问题,拿下多重背包简直小菜一碟. 如果没有看过前两篇01背包和完全背包的文章,强烈建议先阅读一下,因为本文跟前两篇文章关联性很强. 多重背包 有N种物品和一个容量为T的背包,第i种物品最多有M[i]件可用,价值为P[i],体积为V[i],求解:选哪些物品放入背包,可以使得这些物品的价值最大,并且体积总和不超过背包容量. 对比一下完全背包,其实只是多了一

诗经 全文

诗经 全文 (带注释和译文) http://www.edu009.com/Article/HTML/Article_60756.html <诗经> 春秋·孔丘 <诗经>是我国第一部诗歌总集,先秦时代称为“诗”或“诗三百”,孔子加以了整理.汉武帝采纳董仲舒“罢黜百家,独尊儒术”的建议,尊“诗”为经典,定名为<诗经>. <诗经>现存诗歌 305 篇,包括西周初年到春秋中叶共 500 余年的民歌和朝庙乐章,分为风.雅.颂三章. “风”包括周南.召南.邶.鄘.卫.王

关于背包问题(转发两篇文章)

背包九讲系列1--01背包.完全背包.多重背包 https://www.jianshu.com/p/0b9018bbacd7 背包九讲系列2--混合背包.二维费用背包.分组背包 https://www.jianshu.com/p/efa8fbc0fea4 背包九讲系列3--依赖背包.泛化物品.背包变形 https://www.jianshu.com/p/3e0a5f394bcb 原文地址:https://www.cnblogs.com/YY666/p/11360296.html

动态规划之01背包问题(最易理解的讲解)

01背包问题,是用来介绍动态规划算法最经典的例子,网上关于01背包问题的讲解也很多,我写这篇文章力争做到用最简单的方式,最少的公式把01背包问题讲解透彻. 01背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ),  f[i-1,j] } f[i,j]表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值. Pi表示第i件物品的价值. 决策:为了背包中物品总价值最大化,第 i件物品应该放入背包中吗 ? 题目描述: 有编号分别为a,b

算法学习 - 01背包问题(动态规划C++)

动态规划 01背包 问题描述 求解思路 代码实现 放入哪些物品 代码 动态规划 我在上一篇博客里已经讲了一点动态规划了,传送门:算法学习 - 动态规划(DP问题)(C++) 这里说一下,遇到动态规划应该如何去想,才能找到解决办法. 最主要的其实是要找状态转移的方程,例如上一篇博客里面,找的就是当前两条生产线的第i个station的最短时间和上一时刻的时间关系. minTime(station[1][i]) = minTime(station[1][i-1] + time[i], station[

背包问题总结二

上一篇总结了三种基本的背包类型,但做题时很少让直接赤裸裸的求某一种背包.由它们延伸出来的问题可能更加重要. 但只要理解了基本的三种背包,对于更加复杂的问题的理解也不是很难. 仍然参考背包九讲的内容. 混合三种背包 将三种背包混合起来,就是说有的物品只有一件,有的物品有无限件,而有的物品有n[i]件.求把物品装入背包不超过背包容量的最大价值. 听起来很高大上,其实把它们分别开来,对不同类型的问题进行相应的背包即可.. for(int i = 1; i <= N; i++) { if(第i件物品属于

10.动态规划(3)——0-1背包问题

在上一篇<9.动态规划(2)——子集和问题>中,谈到了什么是子集和问题,以及实现.背包问题实际也是子集和问题的一种,不过背包问题不是“判断问题”而是一个“最优问题”.而背包问题实际上又分为“0-1背包”,“完全背包”,本文对“0-1背包”进行讲解. 问题:有n个物品,每个物品的重量为weigh[i],每个物品所对应的价值为price[i],现在有一个背包,背包所能承受的重量为W,问背包能装下的物品总价值最大是多少? 定义s[i, j]表示前i个物品的总价值,j为背包的承重量.当j = W或者最

从01背包问题理解动态规划---初体验

01背包问题具体例子:假设现有容量10kg的背包,另外有3个物品,分别为a1,a2,a3.物品a1重量为3kg,价值为4:物品a2重量为4kg,价值为5:物品a3重量为5kg,价值为6.将哪些物品放入背包可使得背包中的总价值最大? 这个问题有两种解法,动态规划和贪婪算法.本文仅涉及动态规划. 先不套用动态规划的具体定义,试着想,碰见这种题目,怎么解决? 首先想到的,一般是穷举法,一个一个地试,对于数目小的例子适用,如果容量增大,物品增多,这种方法就无用武之地了. 其次,可以先把价值最大的物体放入

动态规划专题 01背包问题详解【转】

对于动态规划,每个刚接触的人都需要一段时间来理解,特别是第一次接触的时候总是想不通为什么这种方法可行,这篇文章就是为了帮助大家理解动态规划,并通过讲解基本的01背包问题来引导读者如何去思考动态规划.本文力求通俗易懂,无异性,不让读者感到迷惑,引导读者去思考,所以如果你在阅读中发现有不通顺的地方,让你产生错误理解的地方,让你难得读懂的地方,请跟贴指出,谢谢! 初识动态规划 经典的01背包问题是这样的: 有一个包和n个物品,包的容量为m,每个物品都有各自的体积和价值,问当从这n个物品中选择多个物品放