acm——背包问题

一、背包问题分类:

  我觉得简单的背包问题分为两类:一是01背包问题:每个物品只有拿或者不拿两种选项;另一种就是非01背包问题,每种物品的重量只要不超过背包的最大容量,可以拿任意多个。

  背包问题还可以按照求最大或者最小分类;

  还可以根据是否一定要充满背包分成充满和不充满;

二、背包问题的一般递推:

  我只知道一种方法:假设我们要求价值最大的值;背包的容量为w;每件物品i的价值为val[i],重量为vol[i];我们先定义f[j]为背包容量为j时,所容物品的价值最大值;所以我们得到f[j]的递推公式:

                            f[j]=max(f[j],f[j-vol[i]]+val[i]);

  当然我们不能马上使用,要根据具体的情况选择不同的方式表达。

  1.首先是一般背包最大值问题,每种物品的重量只要不超过背包的最大容量,可以拿任意多个,同时需要充满背包;

    设有n件物品,背包的容量为w,每件物品i的价值为val[i],重量为vol[i],f[j]为背包容量为j时,所容物品的价值最大值;我们可以这么写:

for(i=1;i<=n;i++)
        {
            for(j=vol[i];j<=w;j++)
            {
                f[j]=max(f[j-vol[i]]+val[i],f[j]);
            }
        }

  2.01背包最大值问题,每个物品只有拿或者不拿两种选项,同时需要充满背包;

    设有n件物品,背包的容量为w,每件物品i的价值为val[i],重量为vol[i],f[j]为背包容量为j时,所容物品的价值最大值;我们可以这么写:

for(i=1;i<=n;i++)
        {
            for(j=w;j>=vol[i];j--)
            {
                f[j]=max(f[j-vol[i]]+val[i],f[j]);
            }
        }

    这里注意,因为是01背包问题,每件物品只能拿一件,所以j从w开始递减,这样保证了每件物品只拿一件。

    同时注意,上面所说的开始时要初始化memset(f,0,sizeof(f));如果背包不能充满,则f[w]=0;

  3.一般背包最大值问题,每种物品的重量只要不超过背包的最大容量,可以拿任意多个,同时不需要充满背包;这里只要一点点改动即可:

for(i=1;i<=n;i++)
        {
            for(j=vol[i];j<=w;j++)
            {
                m=max(f[j-vol[i]]+val[i],f[j]);
                if(f[j]<m)
                     f[j]=m;
            }
        }   

  4.同理,01背包最大值问题,不需要充满背包时:

for(i=1;i<=n;i++)
        {
            for(j=w;j>=vol[i];j--)
            {
                m=max(f[j-vol[i]]+val[i],f[j]);
                if(m>f[j])
                     f[j]=m;
            }
        }

  求最小时,只要将上面的max换成min即可。

这里,以hdu的两道题为:

    hdu2602

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
    int t,n,w,f[1001],vol[1001],val[1001] ,m,i,j;
    scanf("%d",&t);
    while(t--)
    {
        m=0;
        memset(f,0,sizeof(f));
        scanf("%d %d",&n,&w);
        for(i = 1 ; i <= n ; i++)
        scanf("%d",&val[i]);
        for(i = 1 ; i <= n ; i++)
        scanf("%d",&vol[i]);
        for(i = 1 ; i <= n ; i++)
        {
            for(j = w ; j >= vol[i] ; j--)
            {
                m=f[j-vol[i]]+val[i];
                if(f[j]<m)
                    f[j]=m;
            }
        }
        printf("%d\n",f[w]);
    }
    return 0;
}

  hdu1114

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
int main()
{
    int t,n,w,f[10010],vol[1001],val[1001] ,m,i,j,a,b;
    scanf("%d",&t);
    while(t--)
    {
        m=0;
        scanf("%d %d",&a,&b);
        w=b-a;
        for(i=0;i<=w;i++)
            f[i]=500000000;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d%d",&val[i],&vol[i]);
            f[0]=0;
        for(i=1;i<=n;i++)
        {
            for(j=vol[i];j<=w;j++)
            {
                f[j]=min(f[j-vol[i]]+val[i],f[j]);
            }
        }
        if(f[w]==500000000)
            printf("This is impossible.\n");
        else
            printf("The minimum amount of money in the piggy-bank is %d.\n",f[w]);
    }
    return 0;
}
时间: 2025-01-16 17:14:43

acm——背包问题的相关文章

ACM:动态规划,物品无限的背包问题(完全背包问题)

题目:有n种物品,每种物品都有无限件可用.第i种物品的体积是vi,重量是wi.选一些物品装到一个容量为C的背包中,使得背包内物品在总体积不超过C的前提下重量尽量大. 分析,完全背包问题,相对于上上篇文章的硬币问题,只是由DAG上的无权图变成了这里的DAG上的带权图! 输出最后满足体积不超过背包容量的条件下,背包中的最大重量. 代码: #include <iostream> #include <string> using namespace std; const int MAXN =

ACM 01背包问题1

Description Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave … The bone collector had a big bag with a volume of V ,and

ACM 01背包问题

Description The aspiring Roy the Robber has seen a lot of American movies, and knows that the bad guys usually gets caught in the end, often because they become too greedy. He has decided to work in the lucrative business of bank robbery only for a s

HDU ACM 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活-&gt;多重背包问题

分析:多重背包问题.这里直接转换为01背包,为使用二进制. #include<iostream> using namespace std; int price[101]; int weight[101]; int number[101]; int dp[101]; int main() { int C,n,m; int i,j,k; cin>>C; while(C--) { cin>>n>>m; for(i=0;i<m;i++) { cin>&g

ACM:动态规划,01背包问题

题目: 有n件物品和一个容量为C的背包.(每种物品均仅仅有一件)第i件物品的体积是v[i],重量是w[i].选一些物品装到这个背包中,使得背包内物品在整体积不超过C的前提下重量尽量大. 解法:两种思路: 第一种:d(i, j)表示"把第i,i+1,i+2,...n个物品装到容量为j的背包中的接下来的最大总重量". d(i, j) = max{d(i+1, j), d(i+1, j-v[i])+w[i]}     前面一项表示不放第i个物品,后面一项表示放第i个物品. 然后取两者之中最大

HDU ACM 1203 I NEED A OFFER!-&gt;背包问题

分析:最大录取概率=1-最小不录取概率. 0-1背包求出最小不录取概率,然后用1减去即可. 注意dp数组初始化时概率要先设置为1,表示一开始被录取. #include<iostream> using namespace std; double p[10001],dp[10001]; int v[10001]; int main() { int n,m,i,j; while(cin>>n>>m &&(n||m)) { for(i=0;i<m;i++)

HDU ACM 2955 Robberies-&gt;0-1背包问题

题意:Roy想要抢劫银行,每家银行都有一定的金额和被抓到的概率,知道Roy被抓的最大概率P,求Roy在被抓的情况下,抢劫最多. 分析: 1.可以把各个银行的钱数加起来得到总钱数,进而看成背包的容量. 2.各个银行的钱看作重量. 3.不被抓的概率看作价值,注意这里用乘而不是加. 4.因此有状态转移方程:dp[j]=dp[j]>dp[j-mj[i]]*(1-pj[i])?dp[j]:dp[j-mj[i]]*(1-pj[i]); #include<iostream> using namespa

acm常见算法及例题

转自:http://blog.csdn.net/hengjie2009/article/details/7540135 acm常见算法及例题 初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法

ACM学期总结

从大一就开始对这个东西感兴趣,当时其实并不知道ACM是什么,当时学习想法也很简单,就是想用来提高自己的编程能力. 接触ACM已经有了一学期的时间,说时候ACM真的很难学,从一开始的激情满满,到后来的索然无趣.ACM是十分花费时间的东西,平均下来我几乎每道题的的时间差不多就有两个小时,虽然会很打击人信心,但是在某些方面自己的能力确实提高了不少,无论自己在考虑问题,分析问题上,还是对于语言的认识上,考虑的比之前更加全面,分析的比之前更加透彻,ACM便是运用已有的算法,解决更加接近于现实的问题.刷题只