DP学习之路(1)--01背包

动态规划是算法中一门很重要的思想,其通过对每一步的假设规划,不停的寻找最优最有利的解决方案,然后一步一步求解出来。

而01背包是其中最基本的一种dp思想,其题目一般为给定一个容量为V的背包,然后有n件物品,其价值为value[i],每件物品只能最多选择一次或者不选择,问如何才能得到的物品价值最大。

一般dp问题的核心就是一个 状态转移方程 。状态转移方程一出来题目基本上就木得问题了。

通常来说,状态转移方程的代码思想一般如下

for(int i=0; i<n; i++)
{
    for(int j=0; j<=V; j++)
    {
        if(j>=v[i])
            dp[i+1][j] = max(dp[i][j], dp[i][j-v[i]]+val[i]);
        else
            dp[i+1][j] = dp[i][j];
    }
}

来看看这段代码,将第i件物品放在容量为j的背包中,使得dp[i][j]最大,对于第i件物品来说,有两种选择:第一,不放这件物品。如果不放这件物品,则dp[i+1][j]=dp[i][j]。第二,放这件物品。那么首先考虑是否放的下,就是剩下的空间j是否比这件物品的体积v[i]大。如果大,则在j中腾出v[i]的空间给第i个物品,然后加上其价值与dp[i][j]比较一下就好了,取其中的最大值。如果j小于v[i],那么这个物品就不要考虑了,直接丢掉就行了。

先看看基础的题目。

1.hdu 2602

这道题目就是一道裸的不能再裸的01背包,给定的容量V,n件物品,每件价值给定,然后只能选一次。

首先学习到了有两种方法解决这道题,第一种是用二维数组,将每次的中间过程都存储下来,状态转移方程又有两种写法。

1 dp[i+1][j]=max(dp[i][j],dp[i][j-v[i]]+val[i]);
2
3 注意这个是数组从0开始进行for循环
4
5 dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+val[i]);
6
7 这个是数组从1开始进行for循环
8
9 其中v代表体积,val代表价值

以下是二维数组ac代码:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#define ll long long int
#define inf 1000000007
using namespace std;
int main()
{
    int t;
    int val[1010],v[1010];
    int dp[1010][1010];
    cin>>t;
    while(t--)
    {
        int n,V;
        cin>>n>>V;
        for(int i=0;i<n;i++)
            cin>>val[i];
        for(int i=0;i<n;i++)
            cin>>v[i];
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<=V;j++)
            {
                if(j>=v[i])
                    dp[i+1][j]=max(dp[i][j],dp[i][j-v[i]]+val[i]);
                else
                    dp[i+1][j]=dp[i][j];
            }
        }
        cout<<dp[n][V]<<endl;
    }
    return 0;
}

还有另一种的一维数组的代码,一维数组其实就是对上面二维数组的空间优化,具体好像是对空间的一种优化,对于二维数组来说,中间的每一次循环还记录着,而这些数据都是冗余的,可以不用,所以可以用一维数组进行dp。

状态转移方程如下:

for(int i=0; i<n; i++)
{
    for(int j=V; j>=v[i]; j--)
    {
        dp[j] = max(dp[j], dp[j-v[i]]+val[i]);
    }
}

为什么要从V开始递减遍历?我举个例子,假设一个物品GG价值1000,体积为2,那么假设我们按【0…..v】这个顺序遍历,那么在j=2时,dp[2] = max(dp[2], dp[0]+1000),那么dp[2] = 1000,当j=4时,dp[4]=max(dp[4], dp[2]+1000), dp[4] = 2000,这时我们再思考一下,GG将被放进背包两次了!如果我们逆序遍历,就可以避免这种结果。

以下是一维数组ac代码:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cstring>
using namespace std;
int main()
{
    int value[1010],dp[1010],v[1010];
    int t;
    cin>>t;
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        memset(value,0,sizeof(value));
        memset(v,0,sizeof(v));
        int n,V;
        cin>>n>>V;
        for(int i=0;i<n;i++)
        cin>>value[i];
        for(int i=0;i<n;i++)
        cin>>v[i];
        for(int i=0;i<n;i++)   /// i代表的是物体的顺序
         {
            for(int j=V;j>=v[i];j--)   //j代表背包剩余的体积
            {
                dp[j]=max(dp[j],dp[j-v[i]]+value[i]);
            }
        }
        cout<<dp[V]<<endl;
    }
    return 0;
}

2.hdu 2546

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

题意大概就是饭卡的钱如果大于5,就能用,小于5就不能刷了,然后可以透支,如果大于5则可以减去一个数得到负值,问如何买使得剩下的钱最少。

题目思路一般就是先用sort把物品价值排个序,然后把最大的记录下来,然后用dp来使得剩余的钱尽可能的少并且大于5元。

ac代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
using namespace std;
int main()
{
    int val[1010],dp[1010];
    int n,m;
    while(cin>>n&&n)
    {
        memset(dp,0,sizeof(dp));
        memset(val,0,sizeof(val));
        for(int i=0;i<n;i++)
            cin>>val[i];
        sort(val,val+n);
        int maxn=val[n-1];
        cin>>m;
        if(m<5) cout<<m<<endl;
        else
        {
            for(int i=0;i<n-1;i++) //这里要少一个,因为最大的已经记录下来了
                for(int j=m-5;j>=val[i];j--)
                {
                    dp[j]=max(dp[j],dp[j-val[i]]+val[i]);
                }
                cout<<m-maxn-dp[m-5]<<endl;
        }

    }
    return 0;
}

原文地址:https://www.cnblogs.com/wushengyang/p/10050939.html

时间: 2024-11-09 01:45:29

DP学习之路(1)--01背包的相关文章

Re0:DP学习之路 01背包如何打印路径?

伪代码 用二维数组记录,如果出现可以转移的dp那么记录bk[当前体积][装的物品]=1 输出的时候倒推,如果存在连通的边那么输出并且总共的体积减去输出的体积 代码(uva-624,目前wa不明所以,网上的答案也是那么输出的,或许要输出最多的物品?目前也不会这种玩法) #include <bits/stdc++.h> using namespace std; int v[1000],dp[1000000],bk[1000][1000]; int main() { ios::sync_with_s

Python学习之路——基础01篇

安装python编译环境  python数字定义是不需要int,double的,但是数据本身还是包含这些类型,这里是我在学习python过程中的一些代码和心得.   python作为一种高级语言,需要安装自己的解释器,解释你所写的代码然后还需要一个编译器(很多).首先下载一个python编译器,安装完成之后再去python官网下载最新的python 3.X然后安装,点自动设置路径,安装好之后,在计算机cmd界面输入python如果出现:即说明已经安装成功.

Re0:DP学习之路 母牛的故事 HDU - 2018

解法 一定要注意斐波那契数列的原始意义,斐波那契数列也叫作兔子数列是兔子繁衍的一种表示方法.同样适用于别的情况的动物繁衍问题 原始的是3个月一胎现在四个月那么方程就是 f(n)=n n<=4 f(n)=f(n-1)+f(n-3) n>4 代码 #include <bits/stdc++.h> using namespace std; int dp[1000][1000],num[1000][1000]; long long ans[100]; int main() { ios::s

python学习之路基础01

1.python介绍 2.安装 3.第一个python程序 4.变量 5.用户输入 1.python介绍 根据 IEEE Spectrum 发布的研究报告显示,在 2016 年排名第三的 Python 在今年已经成为世界上最受欢迎的语言,C 和 Java 分别位居第二和第三位.由此看出python将是未来语言 2.安装 首先我们进入https://www.python.org  中下载与你系统对应版本的python2.7或者python3.5 3.第一个python程序 运行python,建立一

hdu 4044 GeoDefense (树形dp+01背包)

GeoDefense Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 663    Accepted Submission(s): 267 Problem Description Tower defense is a kind of real-time strategy computer games. The goal of towe

【DP】01背包

(精选上好代码讲解产自原装进口白皮书) 01背包问题 有n个重量和价值分别为wi,vi的物品,从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值. 首先我们用朴素的方式搜索一遍: int rec(int i,int j){ int res; if(i==n) res=0;//已经没有剩余物品了 else if(j<w[i]) res=rec(i+1,j);//无法挑选这个物品 else res=max(rec(i+1,j),rec(i+1,j-w[i])+v[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

poj 1837 01背包

Balance Time Limit: 1000 MS Memory Limit: 30000 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description Gigel has a strange "balance" and he wants to poise it. Actually, the device is different fr

CSU 1547 Rectangle(dp、01背包)

题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1547 Description Now ,there are some rectangles. The area of these rectangles is 1* x or 2 * x ,and now you need find a big enough rectangle( 2 * m) so that you can put all rectangles into it(th