• dp专题训练


    T1:

    Birthday

    内存限制 256MB 时间限制 1S

    程序文件名 birthday.pas/birthday.c/birthday.cpp

    输入文件 birthday.in 输出文件 birthday.out

    前些天是 Miss D 生日,gnaw 去逛街给 Miss D 买礼物。商店有这样的福利:第 i 件商品价值为 Wi,买 k 个(k>0),可以送 Ai × k + Bi 颗 Miss D 喜欢的糖 最大预算为 M 元,最多能赚取多少糖呢?

    输入

    第一行两个整数 N ,M 表示礼物数和最大预算 之后 N 行,表示每件物品的 W A B

    输出 一个整数  表示最多能赚取的糖数

    样例输入

    2 100

    10 2 1

    20 1 1

    样例输出

    21

    数据范围

    30%:

    1 ≤ M ≤ 100

    1 ≤ N ≤ 100

    100%:

    1 ≤ M ≤ 2000

    1 ≤ N ≤ 1000

    0  ≤ Ai, Bi ≤ 2000

    1  ≤ Wi ≤ 2000


     

    题解:当发现不是正常的背包模型时,我们可以考虑直接线性dp

    定义:f [ i ] [ j ]:前i种物品体积为j

    初始化:f [ 0 ][ 0 ]=0;

    转移:也是考虑选与不选嘛(才由前面的状态转移过来)

    当不选的时候就直接像背包一样(直接将前一种状态赋给后面)f [i][j]=f[i-1][j];

    再考虑选的情况:考虑有什么区别(第一次选的时候加的是a+b,多次选就直接加a)

    枚举种类再枚举件数:

    第一次选:f[i] [j-w[i]]=max(f[i-1][j]+a[i]+b[i],f[i][j-w[i]])

    第二次选:f[i][j-w[i]]=max(f[i][j]+a[i],f[i][j-w[i]])


     

    代码:

     

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define N 1002
    #define M 2005
    ll f[N][M];
    int w[N],b[N],a[N];
    int read()
    {
        int sum=0,p=1;char c=getchar();
        while(c<'0'||c>'9')
        {
            if(c=='-') p=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9')
        {
            sum=sum*10+c-'0';
            c=getchar();
        }
        return sum*p;
    }
    int main()
    {
        freopen("birthday.in","r",stdin);
        freopen("birthday.out","w",stdout);
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            w[i]=read(),a[i]=read(),b[i]=read();
        }
        f[0][0]=0;
        for(int i=1;i<=n;i++)//不要被背包蒙蔽,就题分析题,就是普通线性dp,f[i][j]-i为前i选了j个 
        {
            for(int j=m;j>=0;j--) 
            f[i][j]=f[i-1][j];//不选的情况 
            for(int j=m;j>=w[i];j--)//这一步只是在枚举体积而已 
            {
                f[i][j-w[i]]=max(f[i][j-w[i]],f[i-1][j]+a[i]+b[i]);
                f[i][j-w[i]]=max(f[i][j-w[i]],f[i][j]+a[i]);
                //由前面的转移过来 
            }
        }
        ll maxx=0;
        for(int i=0;i<=m;i++)
        {
            maxx=max(f[n][i],maxx);
        }
        printf("%lld
    ",maxx);
    }
    /*
    2 150
    20 2 3
    35 5 2
    */
    /*
    2 40
    5 2 3
    9 5 2
    */
    View Code

    T2告诉我们打状压的时候要注意!!!!!

    1.位运算符一定要打括号 先算术运算,后移位运算,最后位运算。

    2.数组的大小一定要谨慎设置


    T3:

    Miss D 给 gnaw 准备了 n*m 个问题(比如 miss D 最近在追什么电视剧),并让 gnaw 从中选出一个矩形的区域,这个区域中的问题 gnaw 都能答对。Gnaw 只想知道,这个矩形最大面积是多少? 输入

    n m

    之后 n 行 每行有 m 个数据。

    1 表示这个问题 gnaw 会做,0 表示这个问题不会做。 输出 一个数 表示最大全 1 矩形的问题数

    样例输入

    4 4

    0 0 0 0

    0 1 1 0

    0 1 1 0

    0 0 0 0

    样例输出

    4

    50% 1<=n,m<=100

    100% 1<=n,m<=1000


    题解:

    就是裸的最大子矩阵问题:

    考虑使用悬线法:

    h(i,j)i,j 的最大高度 r(i,j) i , j 的右边最近的障碍 l(i,j)i , j的左边最近障碍

    基本思路对于每个固定的h去更新找 l , r 然后用(r-l+1)* h来更新答案


     

    对于有向图的dp为啥要先topo:如果我们用代码实现这个过程,如何确定dp的顺序?
    很显然,一个点的dp值能够被确定,其先决条件是它的所有入点的dp值都已被确定。因此我们需要确定一个点的排列,使得每个点的所有入点都在这个点之前出现。这里用到拓扑排序。拓扑序就是我们的顺序

    还有就是这道题也可以用最长路来求,设置一个超级源点和超级汇点,求超级源点的最长路 d [ ed ] 既是答案

     

  • 相关阅读:
    以太坊解析:默克尔树、世界状态、交易及其他
    IIS6服务器的请求流程(图文&源码)
    IIS6服务器的请求流程(图文&源码)
    IIS6服务器的请求流程(图文&源码)
    IIS6服务器的请求流程(图文&源码)
    DAY1--python入门
    DAY1--python入门
    DAY1--python入门
    DAY1--python入门
    Java中创建对象的5种方式
  • 原文地址:https://www.cnblogs.com/lkx422/p/11636090.html
Copyright © 2020-2023  润新知