背包习题集

一、01背包

题目 有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]

求解将哪些物 品装入背包可使价值总和最大。

基本思路 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。 用子问题定义状态:

           即表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。 则其状态转移方程便是:

                                      f[i][v] =Max { f[i−1][v] ,f[i−1][v−c[i]] + w[i] }

              这个方程非常重要

               把第i个物品在考虑加进去的时候,计算一下,加入这个物品后,背包的价值能不能提高,这就是状态方程              的意义。

1、HDU 2602

Bone Collector

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 68304    Accepted Submission(s): 28515


Problem 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 along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?

 

Input
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
 

Output
One integer per line representing the maximum of the total value (this number will be less than 2 31).
 

Sample Input
 
  
1 5 10 1 2 3 4 5 5 4 3 2 1
 

Sample Output
 
  
14
 


题意:给出N件物品,背包的容量为V,给出每件物品的重量和价值,求背包容量的限制下,能取到的的最大价值

思路,01背包

最基础的背包问题,特点是:每件物品仅有一件,可以选择放或者不放。用子问题定义状态:

即表示前i件物品恰放入容量为v的背包可以获得的最大价值,其状态状态转换方程为:

f[i][v]=Max{ f[i-1][v],f[i-1][v-c[i]]+v[i]}


#include <iostream>
#include<string.h>
#include<algorithm>
using namespace std;



/*
核心代码
for(int i=1;i<=n;i++0
{
    for(it v=V,v>0;v--)
    {
        f[v]=max(f[v],f[v-c[i]+w[i]);
    }
}
*/


int main()
{
    //cout << "Hello world!" << endl;
    int T,N,V;
    int bag[1010],v[1010],w[1010];
    cin>>T;
    int i,j;
    while(T--)
    {
        memset(bag,0,sizeof(bag));
        cin>>N>>V;
        for(int i=0;i<N;i++)
            cin>>v[i];
        for(int i=0;i<N;i++)
            cin>>w[i];
        for(int i=0;i<N;i++)//第i个物品
        {
            for(j=V;j>=w[i];j--)
            {
                bag[j]=max(bag[j],bag[j-w[i]]+v[i]);
            }
        }
        cout<<bag[V]<<endl;
    }
    return 0;
}


2、hdu 2546 饭卡

饭卡

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 34704    Accepted Submission(s): 11911


Problem Description
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
 

Input
多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。

n=0表示数据结束。
 

Output
对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。
 

Sample Input
 
  
1 50 5 10 1 2 3 2 1 1 2 3 2 1 50 0
 

Sample Output
 
  
-45 32


思路:01背包

把饭卡的余额处理成背包的容量,如果卡的余额小于5元,则直接输出卡的余额

否则首先点N-1份菜,求当背包的容量为M-5时,能点的菜的价格的最大值bag[M-5],然后用再减去最贵的菜。


#include <iostream>
#include<string.h>
#include<algorithm>
using namespace std;



/*
核心代码
for(int i=1;i<=n;i++0
{
    for(it v=V,v>0;v--)
    {
        f[v]=max(f[v],f[v-c[i]+w[i]);
    }
}
*/


int main()
{
    //cout << "Hello world!" << endl;
    int N,M;
    int temp;
    int bag[1010],v[1010],w[1010];

    int i,j;


        while(cin>>N&&N!=0)
        {

        memset(bag,0,sizeof(bag));
        for(i=0;i<N;i++)
            {
                cin>>v[i];
                //w[i]=v[i];
            }
            sort(v,v+N);
        cin>>M;
        //要将卡内的余额减到5,最后选取最贵的菜
        temp=M-5;
        //如果卡内的余额小于5,则输出
        if(M<5)
        {
            cout<<M<<endl;
            continue;
        }

        for(i=0;i<N-1;i++)//第i个物品,注意只用N-1个菜
        {
            for(j=temp;j>=v[i];j--)//容量为j的背包
            {
                bag[j]=max(bag[j],bag[j-v[i]]+v[i]);//表示把背包装到这么大的时候能获取的最大值
            }
        }
        //最后的值应为卡的余额-bag[temp]-v[N-1]
        cout<<M-v[N-1]-bag[temp]<<endl;
        }

    return 0;
}



二、完全背包

题目 有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i], 价值是w[i]。求解将哪               些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最 大。
基本思路 这个问题非常类似于01背包问题,所不同的是每种物品有无限件。也就是从每种 物品的角度考虑,与它相                  关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很 多种。如果仍然按照解01背包时                      的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最 大价值。可以按照每种物品不同的                       策略写出状态转移方程:
                                  f[i][v] = max { f[i−1][ v−k×w[i] ] + k×v[i] }          0 <= k×c[i] <= V


             但是实际代码不是这么直接套用的,而是在当前状态下,继续添加当前物品,直到背包装满。


for(int i=0;i<N;i++)
{
    for(int j=w[i];j<=V;j++)//V是背包最大容量
    {
        f[j]=max(f[j],f[j-w[i]]+v[i]);//数组w为重量,v为及价值
    }
}

1、hdu 1114

Piggy-Bank

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 28201    Accepted Submission(s): 14237


Problem Description
Before ACM can do anything, a budget must be prepared and the necessary financial support obtained. The main income for this action comes from Irreversibly Bound Money (IBM). The idea behind is simple. Whenever some ACM member has any small money, he takes all the coins and throws them into a piggy-bank. You know that this process is irreversible, the coins cannot be removed without breaking the pig. After a sufficiently long time, there should be enough cash in the piggy-bank to pay everything that needs to be paid. 

But there is a big problem with piggy-banks. It is not possible to determine how much money is inside. So we might break the pig into pieces only to find out that there is not enough money. Clearly, we want to avoid this unpleasant situation. The only possibility is to weigh the piggy-bank and try to guess how many coins are inside. Assume that we are able to determine the weight of the pig exactly and that we know the weights of all coins of a given currency. Then there is some minimum amount of money in the piggy-bank that we can guarantee. Your task is to find out this worst case and determine the minimum amount of cash inside the piggy-bank. We need your help. No more prematurely broken pigs! 
 

Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing two integers E and F. They indicate the weight of an empty pig and of the pig filled with coins. Both weights are given in grams. No pig will weigh more than 10 kg, that means 1 <= E <= F <= 10000. On the second line of each test case, there is an integer number N (1 <= N <= 500) that gives the number of various coins used in the given currency. Following this are exactly N lines, each specifying one coin type. These lines contain two integers each, Pand W (1 <= P <= 50000, 1 <= W <=10000). P is the value of the coin in monetary units, W is it's weight in grams. 
 

Output
Print exactly one line of output for each test case. The line must contain the sentence "The minimum amount of money in the piggy-bank is X." where X is the minimum amount of money that can be achieved using coins with the given total weight. If the weight cannot be reached exactly, print a line "This is impossible.". 
 

Sample Input
 
  
3 10 110 2 1 1 30 50 10 110 2 1 1 50 30 1 6 2 10 3 20 4
 

Sample Output
 
  
The minimum amount of money in the piggy-bank is 60. The minimum amount of money in the piggy-bank is 100. This is impossible.


思路:

完全背包。每种硬币可以无限放。但是这里不是求最大价值,而是求最小价值,所以我们先假设所有状态为正无穷,然后不断更新dp,以求得最小价值。这样在动态规划时需要注意一点,状态0始终未0,即f [ 0 ] =0恒成立

#include <iostream>

using namespace std;
const int inf=0x6fffffff;
int f[10002];
/*
for(int i=0;i<N;i++)
{
    for(int j=w[i];j<=V;j++)//V是背包最大容量
    {
        f[j]=max(f[j],f[j-w[i]]+v[i]);//数组w为重量,v为及价值
    }
}
*/
int main()
{
    //
    //cout << "Hello world!" << endl;
    int T,E,F,M,N,P,W;
    int i,j;
    cin>>T;


    while(T--)
    {
        for(i=0;i<10002;i++)f[i]=inf;
        f[0]=0;//给动态规划一个开头
        cin>>E>>F;
        M=F-E;
        //
        cin>>N;
        for(i=0;i<N;i++)//第i种硬币
        {
            cin>>P>>W;
            for(j=W;j<=M;j++)//不断往里放钱,取钱最少的方案
            {
                f[j]=min(f[j],f[j-W]+P);
            }
        }
        if(f[M]==inf)
        {
            cout<<"This is impossible."<<endl;

        }
        else
        {
            cout<<"The minimum amount of money in the piggy-bank is "<<f[M]<<"."<<endl;
        }


    }

    return 0;
}




猜你喜欢

转载自blog.csdn.net/fire_to_cheat_/article/details/78635091