01背包专题

>>什么是01背包<<

A - Bone Collector

Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Submit Status

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

>>题目链接<<

题意:给定背包容量,骨头的个数和每个骨头的价值,求在背包容量允许的情况下,最多装的价值。

思路:最基础的01背包,dp[j]=max(dp[j],dp[j-w[i]]+v[i]);

#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
    int N,V,T;

    int w[1005];
    int c[1005];
    int i,j,k;
    scanf("%d",&T);
    while(T--)
    {
        int f[1005]={0};
        scanf("%d%d",&N,&V);
        for(i=0;i<N;i++)
        {
            scanf("%d",&w[i]);
        }
        for(i=0;i<N;i++)
        {
            scanf("%d",&c[i]);
        }

        for(i=0;i<N;i++)
        {
  //          printf("\nc[%d]=%d\tw[%d]=%d\n",i,c[i],i,w[i]);
            for(int v=V;v>=c[i];v--)// 剩下的体积要大于想放入的体积
            {
                f[v]=max(f[v],f[v-c[i]]+w[i]);
 //               printf("v=%d\tf[%d]=%d\n",v,v,f[v]);
            }
        }

    }
    return 0;
}

/*
1
5 10
2 3 4 5 1
4 3 2 1 5*/

写的第一个01背包,写的格式不是很好,见谅!

B - Charm Bracelet

Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

Submit Status

Description

Bessie has gone to the mall‘s jewelry store and spies a charm bracelet. Of course, she‘d like to fill it with the best charms possible from the N (1 ≤ N ≤ 3,402) available charms. Each charm i in the supplied list has a weight Wi (1 ≤ Wi ≤ 400), a ‘desirability‘ factor Di (1 ≤ Di ≤ 100), and can be used at most once. Bessie can only support a charm bracelet whose weight is no more than M (1 ≤ M ≤ 12,880).

Given that weight limit as a constraint and a list of the charms with their weights and desirability rating, deduce the maximum possible sum of ratings.

Input

* Line 1: Two space-separated integers: N and M
* Lines 2..N+1: Line i+1 describes charm i with two space-separated integers: Wi and Di

Output

* Line 1: A single integer that is the greatest sum of charm desirabilities that can be achieved given the weight constraints

Sample Input

4 6
1 4
2 6
3 12
2 7

Sample Output

23

>>题目链接<<

题意:输入N,M,表示下面有N组数据(Wi,Di),要求取数据Wi和超过M,同时Di和最大;

分析:典型的01背包,在背包允许的载重范围内,使得价值最大!

#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
    int N,M;
    int W[3500],D[3500];
    int i,j,k;
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        int f[12885]={0};
        for(i=0;i<N;i++)
        {
            scanf("%d%d",&W[i],&D[i]);
        }

        for(i=0;i<N;i++)
        {
            for(j=M;j>=W[i];j--)
            {
  //              if(f[j]<f[j-W[i]]+D[i])
    //              f[j]=f[j-W[i]]+D[i];
                f[j]=max(f[j],f[j-W[i]]+D[i]);// 注意这里是加上第i的价值哦,不是j;
 //               printf("j=%d\tf[%d]=%d\n",j,j,f[j]);
            }
        }
        printf("%d\n",f[M]);
    }
    return 0;
}

/*
4 6
1 4
2 6
3 12
2 7
*/

C -饭卡

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

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

题意:首先输入菜的种类n,然后第二行输入n种菜的价格,第三行输入饭卡里的余额;如果饭卡里的钱低于5元,不管够不够,都不能付款,否则可以付款,即使钱不够也没关系,求最多可以买多少的菜,然后饭卡里的余额最少;

思路:把最贵的菜先拿出来,然后再01背包,注意这个时候最大的背包数位m-5;注意m小于5的时候是不能购买的;

>>题目链接<<

#include<cstdio>
#include<iostream>
using namespace std;

int main()
{
    int n,i,j,m;
    int c[1005];
    int sum,mmax;
    while(scanf("%d",&n),n)
    {
        sum=0;
        mmax=0;
        int f[1005]= {0};
        for(i=0; i<n; i++)
        {
            scanf("%d",&c[i]);
            sum+=c[i];
            mmax=max(mmax,c[i]);
        }
        scanf("%d",&m);
        if(m<5)
        {
            printf("%d\n",m);
        }
        else if(sum<=m)
            printf("%d\n",m-sum);
        else
        {

            int t=0;
            for(i=0; i<n; i++)
            {
                if(c[i]==mmax)
                {
                    c[i]=0;
                    t=1;
                }
                if(t) break;
            }
            for(i=0; i<n; i++)
            {
                for(j=m-5; j>=c[i]; j--)
                {
                    f[j]=max(f[j],f[j-c[i]]+c[i]);
                }
            }
            printf("%d\n",m-mmax-f[m-5]);
        }

    }
    return 0;
}

D - CD

Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu

Submit Status Practice UVA 624

Appoint description: 
acmparand  (2013-07-30)
System Crawler  (2014-12-09)

Description

 CD 

You have a long drive by car ahead. You have a tape recorder, but unfortunately your best music is on CDs. You need to have it on tapes so the problem to solve is: you have a tape N minutes long. How to choose tracks from CD to get most out of tape space and have as short unused space as possible.

Assumptions:

  • number of tracks on the CD. does not exceed 20
  • no track is longer than N minutes
  • tracks do not repeat
  • length of each track is expressed as an integer number
  • N is also integer

Program should find the set of tracks which fills the tape best and print it in the same sequence as the tracks are stored on the CD

Input

Any number of lines. Each one contains value N, (after space) number of tracks and durations of the tracks. For example from first line in sample data: N=5, number of tracks=3, first track lasts for 1 minute, second one 3 minutes, next one 4 minutes

Output

Set of tracks (and durations) which are the correct solutions and string `` sum:" and sum of duration times.

Sample Input

5 3 1 3 4
10 4 9 8 4 2
20 4 10 5 7 4
90 8 10 23 1 2 3 4 5 7
45 8 4 10 44 43 12 9 8 2

Sample Output

1 4 sum:5
8 2 sum:10
10 5 4 sum:19
10 23 1 2 3 4 5 7 sum:55
4 10 12 9 8 2 sum:45

>>题目链接<<

题意:

这道题给定一个时间上限,然后一个数字N,后面跟着N首歌的时间长度,要我们

求在规定时间w内每首歌都要完整的播放,最多能播放多少时间。一个比较典型的背包问题,

但是要标记出我们选出的歌曲的编号,然后按顺序输出他们的长度,最后输出求的的最长

播放时间。

思路:在经典的背包问题上增加了一个输出路径而已;那么怎么输出路径呢?我们可以从后面往前dp记录vis[i][j]表示i位上体积为j的数,i对应time[i]就是路径;(表达的不好,j=j-time[i]就是上一个最大体积,也就是路径,那么对应的遍历vis是否有标记,有酒读取。。。以此类推。。输出路径。)

#include<cstdio>
#include<iostream>
using namespace std;

int main()
{
    int N,tracks,i,j;
    int time[25];
    while(scanf("%d%d",&N,&tracks)!=EOF)
    {
        int dp[1005]= {0};
        int vis[25][1005]={0};
        for(i=0; i<tracks; i++)
        {
            scanf("%d",&time[i]);
        }

        for(i=tracks-1; i>=0; i--)
        {
            for(j=N; j>=time[i]; j--)
            {
                if(dp[j]<dp[j-time[i]]+time[i])
                {
                    dp[j]=dp[j-time[i]]+time[i];
                    vis[i][j]=1;
        //            printf("vis[%d][%d]\tdp[%d]=%d\n",i,j,j,dp[j]);
                }
            }
        }
        for(i=0,j=dp[N];i<tracks&&j>0;i++)
        {
            if(vis[i][j])
            {
      //          printf("vis[%d][%d]=%d\tdp[%d]=%d\t time[%d]=%d\n",i,j,vis[i][j],j,dp[j],i,time[i]);
                printf("%d ",time[i]);
                j-=time[i];
            }
        }
        printf("sum:%d\n",dp[N]);
    }
    return 0;
}

下面是去掉注释后的运行结果,有助于理解!

当然这道题还可以用状态压缩来做。。。(状态压缩就是把,每个状态表示为01,0表示不包括,1表示包括在内!)不懂的看代码就知道了。。。

#include<cstdio>
#include<iostream>
using namespace std;

int mmax;
int main()
{
    int N,tracks,i,j;
    int time[25];
    while(scanf("%d%d",&N,&tracks)!=EOF)
    {

        for(i=0; i<tracks; i++)
        {
            scanf("%d",&time[i]);
 //           printf("%d \t",time[i]);
        }
    //    printf("\n");
        mmax=(1<<tracks)-1;
        //      printf("mmax=%d\n",mmax);
        int p=0,sum,t,temp=0;
        for(i=mmax; i>0; i--)
        {
            t=0;
            sum=0;
  //          printf("i= %d\n",i);
            for(j=i; j>0;)
            {
                if(j%2)
                    sum+=time[t];
  //              printf("sum= %d \t",sum);
                j/=2;
                t++;
            }
            if(sum<=N&&temp<=sum)
            {
                temp=sum;
                p=i;
            }

        }

        t=0;
        for(j=p; j>0;)
        {
            if(j%2)
                printf("%d ",time[t]);
            j/=2;
            t++;
        }

        printf("sum:%d\n",temp);
    }
    return 0;
}

先写到这里了。。。明天继续更新。。。

时间: 2024-10-07 00:15:25

01背包专题的相关文章

【背包专题】F - Ahui Writes Word hdu3732【01背包+二进制优化】

We all know that English is very important, so Ahui strive for this in order to learn more English words. To know that word has its value and complexity of writing (the length of each word does not exceed 10 by only lowercase letters), Ahui wrote the

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d

17-又见01背包

/*                                        又见01背包时间限制:1000 ms  |  内存限制:65535 KB难度:3 描述        有n个重量和价值分别为wi 和 vi 的 物品,从这些物品中选择总重量不超过 W     的物品,求所有挑选方案中物品价值总和的最大值.    1 <= n <=100    1 <= wi <= 10^7    1 <= vi <= 100    1 <= W <= 10^

HDU - 2602 Bone Collector(01背包讲解)

题意:01背包:有N件物品和一个容量为V的背包.每种物品均只有一件.第i件物品的费用是volume[i],价值是value[i],求解将哪些物品装入背包可使价值总和最大. 分析: 1.构造二维数组:dp[i][j]---前i件物品放入一个容量为j的背包可以获得的最大价值. dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - volume[i]] + value[i]);---(a) (1)dp[i - 1][j]---不放第i件物品,因此前i件物品放入一个容量为

01背包

这里就只放自己刷的题目了,毕竟是弱弱哒 HDU2546:饭卡 1 #include <algorithm> 2 #include <cstdio> 3 4 using namespace std; 5 6 int main() 7 { 8 int n,m; 9 while (~scanf("%d", &n), n) 10 { 11 int f[2013] = {0}, menu[2013] = {0}; 12 for (int i = 1; i <

hdu 1864 01背包 最大报销额

http://acm.hdu.edu.cn/showproblem.php?pid=1864 New~ 欢迎“热爱编程”的高考少年——报考杭州电子科技大学计算机学院关于2015年杭电ACM暑期集训队的选拔 最大报销额 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 18562    Accepted Submission(s): 5459

超大背包(挑战编程之01背包)

先来温习01背包: 01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2--Wn,与之相对应的价值为P1,P2--Pn. 求出获得最大价值的方案. 注意:在本题中,所有的体积值均为整数. 思路: 考虑用动态规划的方法来解决,这里的:阶段是:在前N件物品中,选取若干件物品放入背包中:状态是:在前N件物品中,选取若干件物品放入所剩空间为W的背包中的所能获得的最大价值:决策是:第N件物品放或者不放:由此可以写出动态转移方程:我们用f[i,j]表示在前 i 件物品中选择若干件放

uva10201 - Adventures in Moving - Part IV(01背包)

题目:uva10201 - Adventures in Moving - Part IV(01背包) 题目大意:一辆车要走D距离,然后它有个200L油箱,并且一开始有100L,现在给你一路上你会遇到的加油站,和这个加油站每升油的价钱,要求你最后到终点的时候油需要大于等于100L,问你加油最少的费用.如果到达不了目标地点就输出Impossible. 解题思路:首先要先到达这个加油站,然后就相当这个加油站你选不选择加油,选择加油了那么又要加多少油.dp[j][i]代表到达第i个加油站还有jL油,dp

HDU 2955 Robberies --01背包变形

这题有些巧妙,看了别人的题解才知道做的. 因为按常规思路的话,背包容量为浮点数,,不好存储,且不能直接相加,所以换一种思路,将背包容量与价值互换,即令各银行总值为背包容量,逃跑概率(1-P)为价值,即转化为01背包问题. 此时dp[v]表示抢劫到v块钱成功逃跑的概率,概率相乘. 最后从大到小枚举v,找出概率大于逃跑概率的最大v值,即为最大抢劫的金额. 代码: #include <iostream> #include <cstdio> #include <cstring>